mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00
CDI operator OLM integration:
- Generate OLM related manifests for CDI in _out/manifests/release/olm OLM bundle: - cdi CSV manifest - cdi crd manifest - cdi package manifest - operatorsource manifest - subscription manifest - operatorgroup manifest - Modify cdi-operator role not to be cluster-admin but more specific - Move all final manifests to _out/manifests directory and update travis with new manifests location - Provide API for vendoring CDI OLM manifests generation code Note: - OLM CSV update to be supported in a separate PR - OLM bundle integration in travis is to be supported together with CSV update
This commit is contained in:
parent
9ed8832aa2
commit
f634cdaa17
10
.travis.yml
10
.travis.yml
@ -26,6 +26,7 @@ install:
|
||||
- make generate-verify
|
||||
- make docker
|
||||
- make manifests
|
||||
- make olm-verify
|
||||
- make apidocs
|
||||
|
||||
before_script:
|
||||
@ -75,8 +76,13 @@ deploy:
|
||||
- _out/cmd/cdi-operator/*
|
||||
- _out/cmd/cdi-uploadproxy/*
|
||||
- _out/cmd/cdi-uploadserver/*
|
||||
- manifests/generated/*.yaml
|
||||
- manifests/generated/*.yaml.j2
|
||||
- _out/manifests/*.yaml
|
||||
- _out/manifests/release/*.yaml
|
||||
- _out/manifests/templates/release/*.yaml.j2
|
||||
- _out/manifests/release/olm/*.yaml
|
||||
- _out/manifests/templates/release/olm/*.yaml.j2
|
||||
- _out/manifests/release/olm/bundle/*.yaml
|
||||
- _out/manifests/templates/release/olm/bundle/*.yaml.j2
|
||||
- manifests/example/*
|
||||
- provider: script
|
||||
skip_cleanup: true
|
||||
|
11
Makefile
11
Makefile
@ -15,6 +15,7 @@
|
||||
.PHONY: build build-controller build-importer build-cloner build-apiserver build-uploadproxy build-uploadserver build-operator build-functest-file-image-init build-functest-registry-image-init build-functest \
|
||||
docker docker-controller docker-cloner docker-importer docker-apiserver docker-uploadproxy docker-uploadserver docker-operator docker-functest-image-init docker-functest-image-http docker-functest-registry-populate docker-functest-registry docker-functest-registry-init docker-functest-block-device \
|
||||
cluster-sync cluster-sync-controller cluster-sync-cloner cluster-sync-importer cluster-sync-apiserver cluster-sync-uploadproxy cluster-sync-uploadserver \
|
||||
olm-verify olm-push \
|
||||
test test-functional test-unit test-lint \
|
||||
publish \
|
||||
vet \
|
||||
@ -48,7 +49,7 @@ apidocs:
|
||||
${DO} "./hack/update-codegen.sh && ./hack/gen-swagger-doc/gen-swagger-docs.sh v1alpha1 html"
|
||||
|
||||
build:
|
||||
${DO} "./hack/build/build-go.sh clean && ./hack/build/build-go.sh build ${WHAT} && ./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-cdi-func-test-registry-host.sh && ./hack/build/build-cdi-func-test-block-device.sh && DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} ./hack/build/build-manifests.sh ${WHAT} && ./hack/build/build-copy-artifacts.sh ${WHAT}"
|
||||
${DO} "./hack/build/build-go.sh clean && ./hack/build/build-go.sh build ${WHAT} && ./hack/build/build-cdi-func-test-file-host.sh && ./hack/build/build-cdi-func-test-registry-host.sh && ./hack/build/build-cdi-func-test-block-device.sh && DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} QUAY_NAMESPACE=${QUAY_NAMESPACE} QUAY_REPOSITORY=${QUAY_REPOSITORY} CSV_VERSION=${CSV_VERSION} ./hack/build/build-manifests.sh ${WHAT} && ./hack/build/build-copy-artifacts.sh ${WHAT}"
|
||||
|
||||
build-controller: WHAT = cmd/cdi-controller
|
||||
build-controller: build
|
||||
@ -149,6 +150,12 @@ push-operator: push
|
||||
publish: docker
|
||||
./hack/build/build-docker.sh publish ${WHAT}
|
||||
|
||||
olm-verify:
|
||||
${DO} "./hack/build/olm.sh verify"
|
||||
|
||||
olm-push:
|
||||
${DO} "CSV_VERSION=${CSV_VERSION} QUAY_NAMESPACE=${QUAY_NAMESPACE} QUAY_USERNAME=${QUAY_USERNAME} QUAY_PASSWORD=${QUAY_PASSWORD} QUAY_REPOSITORY=${QUAY_REPOSITORY} ./hack/build/olm.sh push"
|
||||
|
||||
vet:
|
||||
${DO} "./hack/build/build-go.sh vet ${WHAT}"
|
||||
|
||||
@ -156,7 +163,7 @@ format:
|
||||
${DO} "./hack/build/format.sh"
|
||||
|
||||
manifests:
|
||||
${DO} "DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} ./hack/build/build-manifests.sh"
|
||||
${DO} "CSV_VERSION=${CSV_VERSION} QUAY_NAMESPACE=${QUAY_NAMESPACE} QUAY_REPOSITORY=${QUAY_REPOSITORY} DOCKER_REPO=${DOCKER_REPO} DOCKER_TAG=${DOCKER_TAG} VERBOSITY=${VERBOSITY} PULL_POLICY=${PULL_POLICY} ./hack/build/build-manifests.sh"
|
||||
|
||||
goveralls:
|
||||
${DO} "TRAVIS_JOB_ID=${TRAVIS_JOB_ID} TRAVIS_PULL_REQUEST=${TRAVIS_PULL_REQUEST} TRAVIS_BRANCH=${TRAVIS_BRANCH} ./hack/build/goveralls.sh"
|
||||
|
BIN
assets/cdi_logo.png
Normal file
BIN
assets/cdi_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -35,11 +35,16 @@ for i in $(seq 1 ${KUBEVIRT_NUM_NODES}); do
|
||||
./cluster/cli.sh ssh "node$(printf "%02d" ${i})" "sudo sysctl -w user.max_user_namespaces=1024"
|
||||
done
|
||||
|
||||
# Install CDI
|
||||
./cluster/kubectl.sh apply -f ./manifests/generated/cdi-operator.yaml
|
||||
./cluster/kubectl.sh apply -f ./manifests/generated/cdi-operator-cr.yaml
|
||||
|
||||
./cluster/kubectl.sh apply -f "./_out/manifests/release/cdi-operator.yaml"
|
||||
./cluster/kubectl.sh apply -f "./_out/manifests/release/cdi-operator-cr.yaml"
|
||||
|
||||
|
||||
./cluster/kubectl.sh wait cdis.cdi.kubevirt.io/cdi --for=condition=running --timeout=120s
|
||||
|
||||
# Start functional test HTTP server.
|
||||
./cluster/kubectl.sh apply -f ./manifests/generated/file-host.yaml
|
||||
./cluster/kubectl.sh apply -f ./manifests/generated/registry-host.yaml
|
||||
./cluster/kubectl.sh apply -f ./manifests/generated/block-device.yaml
|
||||
./cluster/kubectl.sh apply -f "./_out/manifests/file-host.yaml"
|
||||
./cluster/kubectl.sh apply -f "./_out/manifests/registry-host.yaml"
|
||||
./cluster/kubectl.sh apply -f "./_out/manifests/block-device.yaml"
|
||||
|
||||
|
||||
|
105
doc/cdi-operator-olm.md
Normal file
105
doc/cdi-operator-olm.md
Normal file
@ -0,0 +1,105 @@
|
||||
# OLM (Operator Lifecycle Management) intergartion
|
||||
##OLM Overview
|
||||
https://github.com/kubevirt/kubevirt/blob/master/docs/devel/olm-integration.md
|
||||
|
||||
|
||||
## CDI OLM manifests
|
||||
1. Generate OLM manifests
|
||||
```bash
|
||||
DOCKER_REPO=<repo> DOCKER_TAG=<docker tag> PULL_POLICY=<pull policy> VERBOSITY=<verbosity> CSV_VERSION=<CSV version> QUAY_NAMESPACE=<namespace> QUAY_REPOSITORY=<application name> make manifests
|
||||
```
|
||||
The generated final olm manifests will be located in _out/manifests/release/olm/bundle/_ directory
|
||||
|
||||
Note: there is a structure of operator related manifest
|
||||
- manifests/release - contains operator manifests that can be deployed without olm
|
||||
- manifests/olm - contains additional auxilary manifests that are required when deploying with olm and with olm marketplace
|
||||
- manifests/olm/bundle - contains olm bundle that is to be pushed to quay.io and consumed by marketplace operator
|
||||
2. Verify generated manifests
|
||||
```bash
|
||||
make olm-verify
|
||||
```
|
||||
3. Push the generated verified manifests to quay.io
|
||||
```bash
|
||||
CSV_VERSION=<CSV version> QUAY_USERNAME=<quay account username> QUAY_PASSWORD=<quay account password> QUAY_NAMESPACE=<namespace> QUAY_REPOSITORY=<application name> make olm-push
|
||||
```
|
||||
|
||||
##CDI OLM installation
|
||||
### Prerequisites
|
||||
#### Build OLM manifests and push them to quay
|
||||
- Build OLM manifests and push to quay. Specify your DOCKER_REPO, DOCKER_TAG, QUAY_NAMESPACE, QUAY_REPOSITORY, CSV_VERSION.
|
||||
```bash
|
||||
DOCKER_REPO=<repo> DOCKER_TAG=<docker tag> PULL_POLICY=<pull policy> VERBOSITY=<verbosity> CSV_VERSION=<CSV version> QUAY_NAMESPACE=<namespace> QUAY_REPOSITORY=<application name> make manifests
|
||||
```
|
||||
- Push OLM bundle to quay. Provide QUAY_NAMESPACE, QUAY_REPOSITORY, QUAY_USERNAME, QUAY_PASSWORD, CSV_VERSION
|
||||
```bash
|
||||
QUAY_NAMESPACE=<quay namespace> QUAY_REPOSITORY=<quay repo> QUAY_USERNAME=<quay username> QUAY_PASSWORD=<quay password> CSV_VERSION=<csv version > make olm-push
|
||||
```
|
||||
#### Install OLM and Marketplace operators on cluster
|
||||
- Install OLM operator from cloned operator-lifecycle-manager repo
|
||||
|
||||
```bash
|
||||
kubectl apply -f $GOPATH/src/github.com/operator-framework/operator-lifecycle-manager/deploy/upstream/quickstart/olm.yaml
|
||||
```
|
||||
- Install marketplace operator from cloned operator-marketplace repo
|
||||
```bash
|
||||
kubectl apply -f $GOPATH/src/github.com/operator-framework/operator-marketplace/deploy/upstream/ --validate=false
|
||||
```
|
||||
###CDI installation by means of OLM and Marketplace operators
|
||||
- Install CDI operatorsource manifest that specifies the location of CDI OLM bundle in quay
|
||||
```bash
|
||||
kubectl apply -f _out/manifests/release/olm/cdi-operatorsource.yaml_
|
||||
```
|
||||
- Handle marketplace namespace workarouond
|
||||
|
||||
Move _catalogsourceconfig.operators.coreos.com/cdi_ from _markeplace_ namespace to _olm_ namespace by modifying *targetNamespace* field to 'olm' from 'marketplace'
|
||||
```bash
|
||||
cluster/kubectl.sh get operatorsource,catalogsourceconfig,catalogsource,subscription,installplan --all-namespaces
|
||||
cluster/kubectl.sh edit catalogsourceconfig.operators.coreos.com/cdi -n marketplace
|
||||
```
|
||||
- Create CDI namespace
|
||||
```bash
|
||||
kubectl create ns cdi
|
||||
```
|
||||
- Configure namespace to be allowed to create operators there
|
||||
```bash
|
||||
cluster/kubectl.sh apply -f _out/manifests/release/olm/operatorgroup.yaml
|
||||
```
|
||||
- Install subscription that will point from which channel the app is downloaded
|
||||
```bash
|
||||
cluster/kubectl.sh apply -f _out/manifests/release/olm/cdi-subscription.yaml
|
||||
```
|
||||
- Now cdi-operator starts running but in order for it to succeed we need to deploy cdi cr
|
||||
```bash
|
||||
cluster/kubectl.sh apply -f _out/manifests/release/cdi-operator-cr.yaml
|
||||
```
|
||||
Now the operator should finish its deployment succefully
|
||||
|
||||
###OKD UI
|
||||
- Grant cluster-admin permissions to kube-system:default
|
||||
```bash
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: kube-system-admin
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: ""
|
||||
```
|
||||
|
||||
- Start OKD UI
|
||||
```bash
|
||||
cd $GOPATH/src/github.com/operator-lifecycle-manager/scripts/
|
||||
./run_console_local.sh
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ The standard workflow is performed inside a helper container to normalize the bu
|
||||
|
||||
- `all`: cleans up previous build artifacts, compiles all CDI packages and builds containers
|
||||
- `apidocs`: generate client-go code (same as 'make generate') and swagger docs.
|
||||
- `build`: compile all CDI binary artifacts and generate controller manifest
|
||||
- `build`: compile all CDI binary artifacts and generate controller and operator manifests
|
||||
- `build-controller`: compile cdi-controller binary
|
||||
- `build-importer`: compile cdi-importer binary
|
||||
- `build-apiserver`: compile cdi-apiserver binary
|
||||
@ -82,8 +82,10 @@ The standard workflow is performed inside a helper container to normalize the bu
|
||||
- `generate`: generate client-go deepcopy functions, clientset, listers and informers.
|
||||
- `generate-verify`: generate client-go deepcopy functions, clientset, listers and informers and validate codegen.
|
||||
- `goveralls`: run code coverage tracking system.
|
||||
- `manifests`: generate a cdi-controller manifest in `manifests/generated/`. Accepts [make variables](#make-variables) DOCKER_TAG, DOCKER_REPO, VERBOSITY, and PULL_POLICY
|
||||
- `manifests`: generate a cdi-controller and operator manifests in `_out/manifests/`. Accepts [make variables](#make-variables) DOCKER_TAG, DOCKER_REPO, VERBOSITY, PULL_POLICY, CSV_VERSION, QUAY_REPOSITORY, QUAY_NAMESPACE
|
||||
- `publish`: CI ONLY - this recipe is not intended for use by developers
|
||||
- `olm-verify`: verify generated olm manifests
|
||||
- `olm-push`: push generated operator bundle to quay.io. Accepts [make_variables](#make-variables) CSV_VERSION, QUAY_USER, QUAY_PASSWORD, QUAY_REPOSITORY
|
||||
- `push`: compiles, builds, and pushes to the repo passed in `DOCKER_REPO=<my repo>`
|
||||
- `push-controller`: compile, build, and push cdi-controller
|
||||
- `push-importer`: compile, build, and push cdi-importer
|
||||
@ -112,6 +114,11 @@ These may be passed to a target as `$ make VARIABLE=value target`
|
||||
- `DOCKER_TAG`: (default: latest) Set global version tags for image and manifest creation
|
||||
- `VERBOSITY`: (default: 1) Set global log level verbosity
|
||||
- `PULL_POLICY`: (default: IfNotPresent) Set global CDI pull policy
|
||||
- `CSV_VERSION`: (default: v0.0.0) Set CSV version of cdi-operator for OLM manifests
|
||||
- `QUAY_USERNAME`: (default: N/A) username to quay.io
|
||||
- `QUAY_PASSWORD`: (default: N/A) password for quay.io
|
||||
- `QUAY_NAMESPACE`: (default: kubevirt) namespace where cdi application is located
|
||||
- `QUAY_REPOSITORY`: (default: cdi) application name
|
||||
- `TEST_ARGS`: A variable containing a list of additional ginkgo flags to be passed to functional tests. The string "--test-args=" must prefix the variable value. For example:
|
||||
|
||||
`make TEST_ARGS="--test-args=-ginkgo.noColor=true" test-functional >& foo`.
|
||||
@ -177,22 +184,58 @@ not supported, then you can use the following example to run Functional Tests.
|
||||
```
|
||||
*To customize environment variables see [make targets](#make-targets)*
|
||||
|
||||
- Run the generated latest manfifest
|
||||
- Run the generated latest manifests
|
||||
There are two options to deploy cdi directly via cdi-controller.yaml or to deploy it via operator
|
||||
##### Direct deployment
|
||||
```
|
||||
# kubectl create -f manifests/generated/cdi-controller.yaml
|
||||
|
||||
serviceaccount/cdi-sa created
|
||||
#kubectl create -f ./_out/manifests/cdi-controller.yaml
|
||||
|
||||
namespace/cdi created
|
||||
customresourcedefinition.apiextensions.k8s.io/datavolumes.cdi.kubevirt.io created
|
||||
customresourcedefinition.apiextensions.k8s.io/cdiconfigs.cdi.kubevirt.io created
|
||||
clusterrole.rbac.authorization.k8s.io/cdi created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/cdi-sa created
|
||||
clusterrole.rbac.authorization.k8s.io/cdi-apiserver created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/cdi-apiserver created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/cdi-apiserver-auth-delegator created
|
||||
serviceaccount/cdi-sa created
|
||||
deployment.apps/cdi-deployment created
|
||||
customresourcedefinition.apiextensions.k8s.io/datavolumes.cdi.kubevirt.io created
|
||||
configmap/cdi-insecure-registries created
|
||||
serviceaccount/cdi-apiserver created
|
||||
rolebinding.rbac.authorization.k8s.io/cdi-apiserver created
|
||||
role.rbac.authorization.k8s.io/cdi-apiserver created
|
||||
rolebinding.rbac.authorization.k8s.io/cdi-extension-apiserver-authentication created
|
||||
role.rbac.authorization.k8s.io/cdi-extension-apiserver-authentication created
|
||||
service/cdi-api created
|
||||
deployment.apps/cdi-apiserver created
|
||||
service/cdi-uploadproxy created
|
||||
deployment.apps/cdi-uploadproxy created
|
||||
|
||||
```
|
||||
##### Deployment via operator
|
||||
```
|
||||
#./cluster/kubectl.sh apply -f "./_out/manifests/release/cdi-operator.yaml"
|
||||
namespace/cdi created
|
||||
customresourcedefinition.apiextensions.k8s.io/cdis.cdi.kubevirt.io created
|
||||
configmap/cdi-operator-leader-election-helper created
|
||||
clusterrole.rbac.authorization.k8s.io/cdi.kubevirt.io:operator created
|
||||
serviceaccount/cdi-operator created
|
||||
clusterrole.rbac.authorization.k8s.io/cdi-operator-cluster-permissions created
|
||||
clusterrolebinding.rbac.authorization.k8s.io/cdi-operator created
|
||||
deployment.apps/cdi-operator created
|
||||
|
||||
#./cluster/kubectl.sh apply -f "./_out/manifests/release/cdi-operator-cr.yaml"
|
||||
cdi.cdi.kubevirt.io/cdi created
|
||||
|
||||
```
|
||||
|
||||
4. Build and run the func test servers
|
||||
In order to run fucntional tests the below servers have to be run
|
||||
- *host-file-server* is required by the functional tests and provides an
|
||||
endpoint server for image files and s3 buckets
|
||||
- *registry-server* is required by the functional tests and provides an endpoint server for container images.
|
||||
- *registry-server* is required by the functional tests and provides an endpoint server for container images.
|
||||
Note: for this server to run the follwoing setting is required in each cluster node
|
||||
``` systemctl -w user.max_user_namespaces=1024 ```
|
||||
|
||||
|
||||
Build and Push to registry
|
||||
@ -201,12 +244,14 @@ not supported, then you can use the following example to run Functional Tests.
|
||||
```
|
||||
Generate manifests
|
||||
```
|
||||
# DOCKER_REPO=<repo> DOCKER_TAG=<tag> make manifests
|
||||
# DOCKER_REPO=<repo> DOCKER_TAG=<docker tag> PULL_POLICY=<pull policy> VERBOSITY=<verbosity> CSV_VERSION=<CSV version> QUAY_NAMESPACE=<namespace> QUAY_REPOSITORY=<application name> make manifests
|
||||
```
|
||||
Run servers
|
||||
```
|
||||
# ./cluster/kubectl.sh apply -f ./manifests/generated/file-host.yaml
|
||||
# ./cluster/kubectl.sh apply -f ./manifests/generated/registry-host.yaml
|
||||
# ./cluster/kubectl.sh apply -f ./_out/manifests/file-host.yaml
|
||||
# ./cluster/kubectl.sh apply -f ./_out/manifests/registry-host.yaml
|
||||
# ./cluster/kubectl.sh apply -f ./_out/manifests/block-device.yaml
|
||||
|
||||
```
|
||||
|
||||
5. Run the tests
|
||||
|
@ -18,93 +18,35 @@ script_dir="$(readlink -f $(dirname $0))"
|
||||
source "${script_dir}"/common.sh
|
||||
source "${script_dir}"/config.sh
|
||||
|
||||
templates="$(find "${MANIFEST_TEMPLATE_DIR}" -name "*.in" -type f)"
|
||||
generator="${BIN_DIR}/manifest-generator"
|
||||
|
||||
(cd "${CDI_DIR}/tools/manifest-generator/" && go build -o "${generator}" ./...)
|
||||
|
||||
|
||||
source "${script_dir}"/resource-generator.sh
|
||||
|
||||
|
||||
mkdir -p "${MANIFEST_GENERATED_DIR}/"
|
||||
#generate controller related manifests used to deploy cdi without operator
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "controller-rbac" "cdi-controller.k8s.rbac.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "apiserver-rbac" "cdi-apiserver.k8s.rbac.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "crd-resources" "cdi-resources.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "apiserver" "cdi-apiserver.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "controller" "cdi-controller.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "uploadproxy" "cdi-uploadproxy.yaml"
|
||||
|
||||
for tmpl in ${templates}; do
|
||||
tmpl=$(readlink -f "${tmpl}")
|
||||
outFile=$(basename -s .in "${tmpl}")
|
||||
rm -rf "${MANIFEST_GENERATED_DIR}/${outFile}"
|
||||
(${generator} -template="${tmpl}" \
|
||||
-docker-repo="${DOCKER_REPO}" \
|
||||
-docker-tag="${DOCKER_TAG}" \
|
||||
-controller-image="${CONTROLLER_IMAGE_NAME}" \
|
||||
-importer-image="${IMPORTER_IMAGE_NAME}" \
|
||||
-cloner-image="${CLONER_IMAGE_NAME}" \
|
||||
-apiserver-image=${APISERVER_IMAGE_NAME} \
|
||||
-uploadproxy-image=${UPLOADPROXY_IMAGE_NAME} \
|
||||
-uploadserver-image=${UPLOADSERVER_IMAGE_NAME} \
|
||||
-operator-image=${OPERATOR_IMAGE_NAME} \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="${PULL_POLICY}" \
|
||||
-namespace="${NAMESPACE}"
|
||||
) 1>"${MANIFEST_GENERATED_DIR}/${outFile}"
|
||||
|
||||
(${generator} -template="${tmpl}" \
|
||||
-docker-repo="{{ docker_prefix }}" \
|
||||
-docker-tag="{{ docker_tag }}" \
|
||||
-controller-image="{{ controller_image }}" \
|
||||
-importer-image="{{ importer_image }}" \
|
||||
-cloner-image="{{ cloner_image }}" \
|
||||
-apiserver-image="{{ apiserver_image }}" \
|
||||
-uploadproxy-image="{{ uploadproxy_image }}" \
|
||||
-uploadserver-image="{{ uploadserver_image }}" \
|
||||
-operator-image="{{ operator_image }}" \
|
||||
-verbosity="{{ verbosity }}" \
|
||||
-pull-policy="{{ pull_policy }}" \
|
||||
-namespace="{{ cdi_namespace }}"
|
||||
) 1>"${MANIFEST_GENERATED_DIR}/${outFile}.j2"
|
||||
done
|
||||
#generate operator related manifests used to deploy cdi with operator-framework
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "operator-rbac" "rbac-operator.authorization.k8s.yaml.in"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "operator-deployment" "cdi-operator-deployment.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "operator-cdi-crd" "cdi-crd.yaml"
|
||||
generateResourceManifest $generator $MANIFEST_GENERATED_DIR "operator-configmap-cr" "cdi-configmap-cr.yaml"
|
||||
|
||||
cat > "${MANIFEST_GENERATED_DIR}/cdi-controller.yaml" << EOF
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: cdi
|
||||
EOF
|
||||
#process templated manifests and populate them with generated manifests
|
||||
tempDir=${MANIFEST_TEMPLATE_DIR}
|
||||
processDirTemplates ${tempDir} ${OUT_DIR}/manifests ${OUT_DIR}/manifests/templates ${generator} ${MANIFEST_GENERATED_DIR}
|
||||
processDirTemplates ${tempDir}/release ${OUT_DIR}/manifests/release ${OUT_DIR}/manifests/templates/release ${generator} ${MANIFEST_GENERATED_DIR}
|
||||
processDirTemplates ${tempDir}/release/olm ${OUT_DIR}/manifests/release/olm ${OUT_DIR}/manifests/templates/release/olm ${generator} ${MANIFEST_GENERATED_DIR}
|
||||
processDirTemplates ${tempDir}/release/olm/bundle ${OUT_DIR}/manifests/release/olm/bundle ${OUT_DIR}/manifests/templates/release/olm/bundle ${generator} ${MANIFEST_GENERATED_DIR}
|
||||
|
||||
(${generator} -code-group=everything \
|
||||
-docker-repo="${DOCKER_REPO}" \
|
||||
-docker-tag="${DOCKER_TAG}" \
|
||||
-controller-image="${CONTROLLER_IMAGE_NAME}" \
|
||||
-importer-image="${IMPORTER_IMAGE_NAME}" \
|
||||
-cloner-image="${CLONER_IMAGE_NAME}" \
|
||||
-apiserver-image=${APISERVER_IMAGE_NAME} \
|
||||
-uploadproxy-image=${UPLOADPROXY_IMAGE_NAME} \
|
||||
-uploadserver-image=${UPLOADSERVER_IMAGE_NAME} \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="${PULL_POLICY}" \
|
||||
-namespace="${NAMESPACE}"
|
||||
) 1>>"${MANIFEST_GENERATED_DIR}/cdi-controller.yaml"
|
||||
|
||||
cat > "${MANIFEST_GENERATED_DIR}/cdi-controller.yaml.j2" << EOF
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: {{ cdi_namespace }}
|
||||
EOF
|
||||
|
||||
(${generator} -code-group=everything \
|
||||
-docker-repo="{{ docker_prefix }}" \
|
||||
-docker-tag="{{ docker_tag }}" \
|
||||
-controller-image="{{ controller_image }}" \
|
||||
-importer-image="{{ importer_image }}" \
|
||||
-cloner-image="{{ cloner_image }}" \
|
||||
-apiserver-image="{{ apiserver_image }}" \
|
||||
-uploadproxy-image="{{ uploadproxy_image }}" \
|
||||
-uploadserver-image="{{ uploadserver_image }}" \
|
||||
-verbosity="{{ verbosity }}" \
|
||||
-pull-policy="{{ pull_policy }}" \
|
||||
-namespace="{{ cdi_namespace }}"
|
||||
) 1>>"${MANIFEST_GENERATED_DIR}/cdi-controller.yaml.j2"
|
||||
|
||||
# Remove empty lines at the end of files which are added by go templating
|
||||
find ${MANIFEST_GENERATED_DIR}/ -type f -exec sed -i {} -e '${/^$/d;}' \;
|
||||
|
@ -26,9 +26,10 @@ FUNC_TEST_REGISTRY_POPULATE="cdi-func-test-registry-populate"
|
||||
FUNC_TEST_REGISTRY_INIT="cdi-func-test-registry-init"
|
||||
FUNC_TEST_BLOCK_DEVICE="cdi-func-test-block-device"
|
||||
|
||||
BINARIES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} cmd/${OPERATOR} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_REGISTRY_INIT}"
|
||||
BINARIES="cmd/${OPERATOR} cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} cmd/${OPERATOR} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_REGISTRY_INIT}"
|
||||
CDI_PKGS="cmd/ pkg/ test/"
|
||||
|
||||
OPERATOR_MAIN="cmd/${OPERATOR}"
|
||||
CONTROLLER_MAIN="cmd/${CONTROLLER}"
|
||||
IMPORTER_MAIN="cmd/${IMPORTER}"
|
||||
CLONER_MAIN="cmd/${CLONER}"
|
||||
@ -36,7 +37,7 @@ APISERVER_MAIN="cmd/${APISERVER}"
|
||||
UPLOADPROXY_MAIN="cmd/${UPLOADPROXY}"
|
||||
UPLOADSERVER_MAIN="cmd/${UPLOADSERVER}"
|
||||
|
||||
DOCKER_IMAGES="cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} cmd/${OPERATOR} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_HTTP} tools/${FUNC_TEST_REGISTRY} tools/${FUNC_TEST_REGISTRY_POPULATE} tools/${FUNC_TEST_REGISTRY_INIT} tools/${FUNC_TEST_BLOCK_DEVICE}"
|
||||
DOCKER_IMAGES="cmd/${OPERATOR} cmd/${CONTROLLER} cmd/${IMPORTER} cmd/${CLONER} cmd/${APISERVER} cmd/${UPLOADPROXY} cmd/${UPLOADSERVER} cmd/${OPERATOR} tools/${FUNC_TEST_INIT} tools/${FUNC_TEST_HTTP} tools/${FUNC_TEST_REGISTRY} tools/${FUNC_TEST_REGISTRY_POPULATE} tools/${FUNC_TEST_REGISTRY_INIT} tools/${FUNC_TEST_BLOCK_DEVICE}"
|
||||
DOCKER_REPO=${DOCKER_REPO:-kubevirt}
|
||||
CONTROLLER_IMAGE_NAME=${CONTROLLER_IMAGE_NAME:-cdi-controller}
|
||||
IMPORTER_IMAGE_NAME=${IMPORTER_IMAGE_NAME:-cdi-importer}
|
||||
@ -49,6 +50,10 @@ DOCKER_TAG=${DOCKER_TAG:-latest}
|
||||
VERBOSITY=${VERBOSITY:-1}
|
||||
PULL_POLICY=${PULL_POLICY:-IfNotPresent}
|
||||
NAMESPACE=${NAMESPACE:-cdi}
|
||||
CSV_VERSION=${CSV_VERSION:-0.0.0}
|
||||
QUAY_REPOSITORY=${QUAY_REPOSITORY:-cdi}
|
||||
QUAY_NAMESPACE=${QUAY_NAMESPACE:-kubevirt}
|
||||
CDI_LOGO_PATH=${CDI_LOGO_PATH:-"assets/cdi_logo.png"}
|
||||
|
||||
KUBERNETES_IMAGE="k8s-1.13.3@sha256:bc0f02d6b970650eb16d12f97e5aa1376b3a13b0ffed6227db98675be2ca1184"
|
||||
OPENSHIFT_IMAGE="os-3.11.0-crio@sha256:3f11a6f437fcdf2d70de4fcc31e0383656f994d0d05f9a83face114ea7254bc0"
|
||||
|
@ -1,6 +1,8 @@
|
||||
FROM fedora:29
|
||||
|
||||
RUN dnf install -y qemu xz gzip git gradle gcc && dnf clean all
|
||||
RUN dnf install -y qemu xz gzip git gradle gcc autoconf automake libtool python jq && dnf clean all
|
||||
|
||||
RUN pip3 install j2cli && pip3 install operator-courier
|
||||
|
||||
ENV GIMME_GO_VERSION=1.11.5 GOPATH="/go" KUBEBUILDER_VERSION="1.0.7" ARCH="amd64"
|
||||
|
||||
|
73
hack/build/olm.sh
Executable file
73
hack/build/olm.sh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# This file is part of the KubeVirt project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
source $(dirname "$0")/common.sh
|
||||
source $(dirname "$0")/config.sh
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "usage: ${0} verify | push"
|
||||
fi
|
||||
|
||||
BUNDLE_DIR=${OUT_DIR}/manifests/release/olm/bundle
|
||||
echo "using these manifests:"
|
||||
ls ${BUNDLE_DIR}
|
||||
|
||||
case ${1} in
|
||||
|
||||
verify)
|
||||
|
||||
IFS=
|
||||
result=$(operator-courier verify ${BUNDLE_DIR} 2>&1)
|
||||
echo $result
|
||||
|
||||
if [[ $result =~ "ERROR" ]]; then
|
||||
echo "olm verify failed!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "olm verify success!"
|
||||
exit 0
|
||||
|
||||
;;
|
||||
|
||||
push)
|
||||
|
||||
if [[ -z "$QUAY_USERNAME" ]] || [[ -z "$QUAY_USERNAME" ]]; then
|
||||
echo "please set QUAY_USERNAME, QUAY_PASSWORD"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "getting auth token from Quay"
|
||||
AUTH_TOKEN=$(curl -sH "Content-Type: application/json" -XPOST https://quay.io/cnr/api/v1/users/login -d '
|
||||
{
|
||||
"user": {
|
||||
"username": "'"${QUAY_USERNAME}"'",
|
||||
"password": "'"${QUAY_PASSWORD}"'"
|
||||
}
|
||||
}' | jq -r '.token')
|
||||
|
||||
echo "pushing bundle"
|
||||
|
||||
operator-courier push ${BUNDLE_DIR} ${QUAY_NAMESPACE} ${QUAY_REPOSITORY} ${CSV_VERSION} "$AUTH_TOKEN"
|
||||
|
||||
;;
|
||||
esac
|
||||
|
159
hack/build/resource-generator.sh
Executable file
159
hack/build/resource-generator.sh
Executable file
@ -0,0 +1,159 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Licensed under the Apache License, Version 2.0 (the "License");
|
||||
#you may not use this file except in compliance with the License.
|
||||
#You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
#Unless required by applicable law or agreed to in writing, software
|
||||
#distributed under the License is distributed on an "AS IS" BASIS,
|
||||
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#See the License for the specific language governing permissions and
|
||||
#limitations under the License.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="$(readlink -f $(dirname $0))"
|
||||
source "${script_dir}"/common.sh
|
||||
source "${script_dir}"/config.sh
|
||||
|
||||
#all generated files are placed in manifests/generated
|
||||
function generateResourceManifest {
|
||||
codeGroup=$3
|
||||
filename=$4
|
||||
generator=$1
|
||||
targetDir=$2
|
||||
|
||||
manifestName=$filename
|
||||
manifestNamej2=$filename".j2"
|
||||
|
||||
rm -rf ${targetDir}/$manifestName
|
||||
rm -rf ${targetDir}/$manifestNamej2
|
||||
(${generator} -code-group=${codeGroup} \
|
||||
-docker-repo="${DOCKER_REPO}" \
|
||||
-docker-tag="${DOCKER_TAG}" \
|
||||
-deploy-cluster-resources="true" \
|
||||
-operator-image="${OPERATOR_IMAGE_NAME}" \
|
||||
-controller-image="${CONTROLLER_IMAGE_NAME}" \
|
||||
-importer-image="${IMPORTER_IMAGE_NAME}" \
|
||||
-cloner-image="${CLONER_IMAGE_NAME}" \
|
||||
-apiserver-image=${APISERVER_IMAGE_NAME} \
|
||||
-uploadproxy-image=${UPLOADPROXY_IMAGE_NAME} \
|
||||
-uploadserver-image=${UPLOADSERVER_IMAGE_NAME} \
|
||||
-csv-version=${CSV_VERSION} \
|
||||
-cdi-logo-path=${CDI_LOGO_PATH} \
|
||||
-quay-namespace="${QUAY_NAMESPACE}" \
|
||||
-quay-repository="${QUAY_REPOSITORY}" \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="${PULL_POLICY}" \
|
||||
-namespace="${NAMESPACE}"
|
||||
) 1>>"${targetDir}/"$manifestName
|
||||
|
||||
(${generator} -code-group=${codeGroup} \
|
||||
-docker-repo="{{ docker_prefix }}" \
|
||||
-docker-tag="{{ docker_tag }}" \
|
||||
-deploy-cluster-resources="true" \
|
||||
-operator-image="{{ operator_image_name }}" \
|
||||
-controller-image="{{ controller_image }}" \
|
||||
-importer-image="{{ importer_image }}" \
|
||||
-cloner-image="{{ cloner_image }}" \
|
||||
-apiserver-image="{{ apiserver_image }}" \
|
||||
-uploadproxy-image="{{ uploadproxy_image }}" \
|
||||
-uploadserver-image="{{ uploadserver_image }}" \
|
||||
-csv-version=${CSV_VERSION} \
|
||||
-cdi-logo-path=${CDI_LOGO_PATH} \
|
||||
-quay-namespace="{{ quay_namespace }}}" \
|
||||
-quay-repository="{{ quay_repository }}}" \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="{{ pull_policy }}" \
|
||||
-namespace="{{ cdi_namespace }}"
|
||||
) 1>>"${targetDir}/"$manifestNamej2
|
||||
|
||||
# Remove empty lines at the end of files which are added by go templating
|
||||
find ${targetDir}/ -type f -exec sed -i {} -e '${/^$/d;}' \;
|
||||
}
|
||||
|
||||
function processDirTemplates {
|
||||
inTmplPath=$1 #Path to directory from which to take manifests templates for processing
|
||||
outFinalManifestPath=$2 #Path to which to store final manifests version
|
||||
outTmplPath=$3 #Path to which to store templated manifests version
|
||||
generator=$4 #generator binary
|
||||
genManifestsDir=$5 #path where manifests generated from code are stored
|
||||
|
||||
rm -rf $outFinalManifestPath
|
||||
rm -rf $outTmplPath
|
||||
mkdir -p $outFinalManifestPath
|
||||
mkdir -p $outTmplPath
|
||||
|
||||
templates="$(find "${inTmplPath}" -maxdepth 1 -name "*.in" -type f)"
|
||||
for tmpl in ${templates}; do
|
||||
tmpl=$(readlink -f "${tmpl}")
|
||||
populateResourceManifest $generator $outFinalManifestPath $outTmplPath $tmpl $genManifestsDir
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# all templated final manifsets are located in _out/manifests/
|
||||
# all templated manifsets are located in _out/manifests/templates
|
||||
function populateResourceManifest {
|
||||
tmpl=$4
|
||||
generator=$1
|
||||
targetDir=$2
|
||||
tmplTargetDir=$3
|
||||
generatedManifests=$5
|
||||
|
||||
outfile=$(basename -s .in "${tmpl}")
|
||||
|
||||
if [[ $tmpl == *"VERSION"* ]]; then
|
||||
outfile=${outfile/VERSION/${CSV_VERSION}}
|
||||
fi
|
||||
(${generator} -template="${tmpl}" \
|
||||
-docker-repo="${DOCKER_REPO}" \
|
||||
-docker-tag="${DOCKER_TAG}" \
|
||||
-deploy-cluster-resources="true" \
|
||||
-operator-image="${OPERATOR_IMAGE_NAME}" \
|
||||
-controller-image="${CONTROLLER_IMAGE_NAME}" \
|
||||
-importer-image="${IMPORTER_IMAGE_NAME}" \
|
||||
-cloner-image="${CLONER_IMAGE_NAME}" \
|
||||
-apiserver-image=${APISERVER_IMAGE_NAME} \
|
||||
-uploadproxy-image=${UPLOADPROXY_IMAGE_NAME} \
|
||||
-uploadserver-image=${UPLOADSERVER_IMAGE_NAME} \
|
||||
-csv-version=${CSV_VERSION} \
|
||||
-cdi-logo-path=${CDI_LOGO_PATH} \
|
||||
-generated-manifests-path=${generatedManifests} \
|
||||
-quay-namespace="${QUAY_NAMESPACE}" \
|
||||
-quay-repository="${QUAY_REPOSITORY}" \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="${PULL_POLICY}" \
|
||||
-namespace="${NAMESPACE}"
|
||||
) 1>>"${targetDir}/"$outfile
|
||||
|
||||
(${generator} -template="${tmpl}" \
|
||||
-docker-repo="{{ docker_prefix }}" \
|
||||
-docker-tag="{{ docker_tag }}" \
|
||||
-deploy-cluster-resources="true" \
|
||||
-operator-image="{{ operator_image_name }}" \
|
||||
-controller-image="{{ controller_image }}" \
|
||||
-importer-image="{{ importer_image }}" \
|
||||
-cloner-image="{{ cloner_image }}" \
|
||||
-apiserver-image="{{ apiserver_image }}" \
|
||||
-uploadproxy-image="{{ uploadproxy_image }}" \
|
||||
-uploadserver-image="{{ uploadserver_image }}" \
|
||||
-csv-version=${CSV_VERSION} \
|
||||
-cdi-logo-path=${CDI_LOGO_PATH} \
|
||||
-generated-manifests-path=${generatedManifests} \
|
||||
-quay-namespace="{{ quay_namespace }}" \
|
||||
-quay-namespace="{{ quay_repository }}" \
|
||||
-verbosity="${VERBOSITY}" \
|
||||
-pull-policy="{{ pull_policy }}" \
|
||||
-namespace="{{ cdi_namespace }}"
|
||||
) 1>>"${tmplTargetDir}/"$outfile".j2"
|
||||
|
||||
# Remove empty lines at the end of files which are added by go templating
|
||||
find ${targetDir}/ -type f -exec sed -i {} -e '${/^$/d;}' \;
|
||||
find ${tmplTargetDir}/ -type f -exec sed -i {} -e '${/^$/d;}' \;
|
||||
}
|
||||
|
||||
|
||||
|
14
manifests/templates/cdi-controller.yaml.in
Normal file
14
manifests/templates/cdi-controller.yaml.in
Normal file
@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: {{.Namespace}}
|
||||
{{index .GeneratedManifests "cdi-resources.yaml"}}
|
||||
{{index .GeneratedManifests ""}}
|
||||
{{index .GeneratedManifests "cdi-controller.k8s.rbac.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-apiserver.k8s.rbac.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-controller.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-apiserver.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-uploadproxy.yaml"}}
|
||||
|
@ -1,103 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: {{.Namespace}}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: cdi-operator
|
||||
namespace: {{ .Namespace }}
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: cdi-operator
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: cdi-operator
|
||||
namespace: {{ .Namespace }}
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
apiGroup: ""
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: "cdi-operator-leader-election-helper"
|
||||
namespace: {{ .Namespace }}
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cdi-operator
|
||||
namespace: {{ .Namespace }}
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
name: cdi-operator
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: cdi-operator
|
||||
operator.cdi.kubevirt.io: ""
|
||||
spec:
|
||||
serviceAccountName: cdi-operator
|
||||
containers:
|
||||
- name: cdi-operator
|
||||
image: {{ .DockerRepo }}/{{ .OperatorImage }}:{{ .DockerTag }}
|
||||
ports:
|
||||
- containerPort: 60000
|
||||
name: metrics
|
||||
imagePullPolicy: {{ .PullPolicy }}
|
||||
env:
|
||||
- name: DEPLOY_CLUSTER_RESOURCES
|
||||
value: 'true'
|
||||
- name: DOCKER_REPO
|
||||
value: {{ .DockerRepo }}
|
||||
- name: DOCKER_TAG
|
||||
value: {{ .DockerTag }}
|
||||
- name: CONTROLLER_IMAGE
|
||||
value: {{ .ControllerImage }}
|
||||
- name: IMPORTER_IMAGE
|
||||
value: {{ .ImporterImage }}
|
||||
- name: CLONER_IMAGE
|
||||
value: {{ .ClonerImage }}
|
||||
- name: APISERVER_IMAGE
|
||||
value: {{ .APIServerImage }}
|
||||
- name: UPLOAD_PROXY_IMAGE
|
||||
value: {{ .UploadProxyImage }}
|
||||
- name: UPLOAD_SERVER_IMAGE
|
||||
value: {{ .UploadServerImage }}
|
||||
- name: VERBOSITY
|
||||
value: '{{ .Verbosity }}'
|
||||
- name: PULL_POLICY
|
||||
value: {{ .PullPolicy }}
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: cdis.cdi.kubevirt.io
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
spec:
|
||||
group: cdi.kubevirt.io
|
||||
names:
|
||||
kind: CDI
|
||||
listKind: CDIList
|
||||
plural: cdis
|
||||
singular: cdi
|
||||
scope: Cluster
|
||||
version: v1alpha1
|
@ -90,4 +90,3 @@ spec:
|
||||
- name: sec-docker-reg
|
||||
port: 443
|
||||
targetPort: 443
|
||||
|
||||
|
@ -2,3 +2,6 @@ apiVersion: cdi.kubevirt.io/v1alpha1
|
||||
kind: CDI
|
||||
metadata:
|
||||
name: cdi
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
imagePullPolicy: {{.PullPolicy}}
|
31
manifests/templates/release/cdi-operator.yaml.in
Normal file
31
manifests/templates/release/cdi-operator.yaml.in
Normal file
@ -0,0 +1,31 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: {{.Namespace}}
|
||||
{{index .GeneratedManifests "cdi-crd.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-configmap-cr.yaml"}}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: cdi.kubevirt.io:operator
|
||||
labels:
|
||||
operator.cdi.kubevirt.io: ""
|
||||
rbac.authorization.k8s.io/aggregate-to-admin: "true"
|
||||
rules:
|
||||
- apiGroups:
|
||||
- cdi.kubevirt.io
|
||||
resources:
|
||||
- cdis
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
- get
|
||||
- list
|
||||
- delete
|
||||
- watch
|
||||
- deletecollection
|
||||
{{index .GeneratedManifests "rbac-operator.authorization.k8s.yaml.in"}}
|
||||
{{index .GeneratedManifests "cdi-operator-deployment.yaml"}}
|
1
manifests/templates/release/olm/bundle/cdi-crds.yaml.in
Normal file
1
manifests/templates/release/olm/bundle/cdi-crds.yaml.in
Normal file
@ -0,0 +1 @@
|
||||
{{index .GeneratedManifests "cdi-crd.yaml"}}
|
@ -0,0 +1,4 @@
|
||||
packageName: {{.QuayRepository}}
|
||||
channels:
|
||||
- name: beta
|
||||
currentCSV: cdioperator.{{.CsvVersion}}
|
@ -0,0 +1,126 @@
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: ClusterServiceVersion
|
||||
metadata:
|
||||
name: cdioperator.{{.CsvVersion}}
|
||||
namespace: placeholder
|
||||
annotations:
|
||||
capabilities: "Full Lifecycle"
|
||||
categories: "Storage,Virtualization"
|
||||
alm-examples: |
|
||||
[
|
||||
{
|
||||
"apiVersion":"cdi.kubevirt.io/v1alpha1",
|
||||
"kind":"CDI",
|
||||
"metadata": {
|
||||
"name":"cdi",
|
||||
"namespace":"cdi"
|
||||
},
|
||||
"spec": {
|
||||
"imagePullPolicy":"IfNotPresent"
|
||||
}
|
||||
}
|
||||
]
|
||||
description: Creates and maintains CDI deployments
|
||||
spec:
|
||||
displayName: CDI
|
||||
description: |
|
||||
CDI is a kubernetes extension that provides the ability to populate PVCs with VM images upon creation. Multiple image formats and sources are supported
|
||||
|
||||
_The CDI Operator does not support updates yet._
|
||||
keywords:
|
||||
- CDI
|
||||
- Virtualization
|
||||
- Storage
|
||||
version: {{.CsvVersion}}
|
||||
maturity: alpha
|
||||
{{.ReplacesCsvVersion}}
|
||||
maintainers:
|
||||
- name: KubeVirt project
|
||||
email: kubevirt-dev@googlegroups.com
|
||||
provider:
|
||||
name: KubeVirt/CDI project
|
||||
links:
|
||||
- name: CDI
|
||||
url: https://github.com/kubevirt/containerized-data-importer/blob/master/README.md
|
||||
- name: Source Code
|
||||
url: https://github.com/kubevirt/containerized-data-importer
|
||||
icon:
|
||||
- base64data: {{.CDILogo}}
|
||||
mediatype: image/png
|
||||
labels:
|
||||
alm-owner-cdi: cdi-operator
|
||||
operated-by: cdi-operator
|
||||
selector:
|
||||
matchLabels:
|
||||
alm-owner-cdi: cdi-operator
|
||||
operated-by: cdi-operator
|
||||
installModes:
|
||||
- type: OwnNamespace
|
||||
supported: true
|
||||
- type: SingleNamespace
|
||||
supported: true
|
||||
- type: MultiNamespace
|
||||
supported: true
|
||||
- type: AllNamespaces
|
||||
supported: true
|
||||
install:
|
||||
strategy: deployment
|
||||
spec:
|
||||
clusterPermissions:
|
||||
- serviceAccountName: cdi-operator
|
||||
rules:
|
||||
{{.OperatorRules}}
|
||||
deployments:
|
||||
- name: cdi-operator
|
||||
spec:
|
||||
{{.OperatorDeploymentSpec}}
|
||||
customresourcedefinitions:
|
||||
owned:
|
||||
- name: cdis.cdi.kubevirt.io
|
||||
version: v1alpha1
|
||||
kind: CDI
|
||||
displayName: CDI deployment
|
||||
description: Represents a CDI deployment.
|
||||
resources:
|
||||
- kind: ConfigMap
|
||||
name: cdi-operator-leader-election-helper
|
||||
version: v1
|
||||
specDescriptors:
|
||||
- description: The ImageRegistry to use for the CDI components.
|
||||
displayName: ImageRegistry
|
||||
path: imageRegistry
|
||||
x-descriptors:
|
||||
- 'urn:alm:descriptor:text'
|
||||
- description: The ImageTag to use for the CDI components.
|
||||
displayName: ImageTag
|
||||
path: imageTag
|
||||
x-descriptors:
|
||||
- 'urn:alm:descriptor:text'
|
||||
- description: The ImagePullPolicy to use for the CDI components.
|
||||
displayName: ImagePullPolicy
|
||||
path: imagePullPolicy
|
||||
x-descriptors:
|
||||
- 'urn:alm:descriptor:io.kubernetes:imagePullPolicy'
|
||||
statusDescriptors:
|
||||
- description: The deployment phase.
|
||||
displayName: Phase
|
||||
path: phase
|
||||
x-descriptors:
|
||||
- 'urn:alm:descriptor:io.kubernetes.phase'
|
||||
- description: Explanation for the current status of the CDI deployment.
|
||||
displayName: Condition
|
||||
path: CDICondition
|
||||
x-descriptors:
|
||||
- 'urn:alm:descriptor:io.kubernetes.conditions'
|
||||
- description: The observed version of the CDI deployment.
|
||||
displayName: Observed CDI Version
|
||||
path: observedVersion
|
||||
- 'urn:alm:descriptor:text'
|
||||
- description: The targeted version of the CDI deployment.
|
||||
displayName: Target CDI Version
|
||||
path: targetVersion
|
||||
- 'urn:alm:descriptor:text'
|
||||
- description: The version of the CDI Operator.
|
||||
displayName: CDI Operator Version
|
||||
path: operatorVersion
|
||||
- 'urn:alm:descriptor:text'
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
cdi.kubevirt.io: ""
|
||||
name: {{.Namespace}}
|
||||
{{index .GeneratedManifests "cdi-crd.yaml"}}
|
||||
{{index .GeneratedManifests "cdi-configmap-cr.yaml"}}
|
||||
{{index .GeneratedManifests "rbac-operator.authorization.k8s.yaml.in"}}
|
||||
|
12
manifests/templates/release/olm/cdi-operatorsource.yaml.in
Normal file
12
manifests/templates/release/olm/cdi-operatorsource.yaml.in
Normal file
@ -0,0 +1,12 @@
|
||||
apiVersion: operators.coreos.com/v1
|
||||
kind: OperatorSource
|
||||
metadata:
|
||||
name: cdi
|
||||
namespace: marketplace
|
||||
spec:
|
||||
type: appregistry
|
||||
endpoint: https://quay.io/cnr
|
||||
registryNamespace: {{.QuayNamespace}}
|
||||
displayName: "CDI"
|
||||
publisher: "CDI project"
|
||||
|
10
manifests/templates/release/olm/cdi-subscription.yaml.in
Normal file
10
manifests/templates/release/olm/cdi-subscription.yaml.in
Normal file
@ -0,0 +1,10 @@
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: cdi
|
||||
namespace: {{.Namespace}}
|
||||
spec:
|
||||
channel: beta
|
||||
name: cdi
|
||||
source: cdi
|
||||
sourceNamespace: olm
|
5
manifests/templates/release/olm/operatorgroup.yaml.in
Normal file
5
manifests/templates/release/olm/operatorgroup.yaml.in
Normal file
@ -0,0 +1,5 @@
|
||||
apiVersion: operators.coreos.com/v1alpha2
|
||||
kind: OperatorGroup
|
||||
metadata:
|
||||
name: {{.Namespace}}
|
||||
namespace: {{.Namespace}}
|
@ -68,16 +68,17 @@ type args struct {
|
||||
|
||||
var (
|
||||
envVars = map[string]string{
|
||||
"DOCKER_REPO": "kubevirt",
|
||||
"DOCKER_TAG": version,
|
||||
"CONTROLLER_IMAGE": "cdi-controller",
|
||||
"IMPORTER_IMAGE": "cdi-importer",
|
||||
"CLONER_IMAGE": "cdi-cloner",
|
||||
"UPLOAD_PROXY_IMAGE": "cdi-uploadproxy",
|
||||
"UPLOAD_SERVER_IMAGE": "cdi-uploadserver",
|
||||
"APISERVER_IMAGE": "cdi-apiserver",
|
||||
"VERBOSITY": "1",
|
||||
"PULL_POLICY": "Always",
|
||||
"DOCKER_REPO": "kubevirt",
|
||||
"DOCKER_TAG": version,
|
||||
"DEPLOY_CLUSTER_RESOURCES": "true",
|
||||
"CONTROLLER_IMAGE": "cdi-controller",
|
||||
"IMPORTER_IMAGE": "cdi-importer",
|
||||
"CLONER_IMAGE": "cdi-cloner",
|
||||
"UPLOAD_PROXY_IMAGE": "cdi-uploadproxy",
|
||||
"UPLOAD_SERVER_IMAGE": "cdi-uploadserver",
|
||||
"APISERVER_IMAGE": "cdi-apiserver",
|
||||
"VERBOSITY": "1",
|
||||
"PULL_POLICY": "Always",
|
||||
}
|
||||
)
|
||||
|
||||
@ -593,17 +594,18 @@ func createReconciler(client realClient.Client) *ReconcileCDI {
|
||||
namespace := "cdi"
|
||||
clusterArgs := &clusterResources.FactoryArgs{Namespace: namespace}
|
||||
namespacedArgs := &namespaceResources.FactoryArgs{
|
||||
DockerRepo: "kubevirt",
|
||||
DockerTag: version,
|
||||
ControllerImage: "cdi-controller",
|
||||
ImporterImage: "cdi-importer",
|
||||
ClonerImage: "cdi-cloner",
|
||||
APIServerImage: "cdi-apiserver",
|
||||
UploadProxyImage: "cdi-uploadproxy",
|
||||
UploadServerImage: "cdi-uploadserver",
|
||||
Verbosity: "1",
|
||||
PullPolicy: "Always",
|
||||
Namespace: namespace,
|
||||
DockerRepo: "kubevirt",
|
||||
DockerTag: version,
|
||||
DeployClusterResources: "true",
|
||||
ControllerImage: "cdi-controller",
|
||||
ImporterImage: "cdi-importer",
|
||||
ClonerImage: "cdi-cloner",
|
||||
APIServerImage: "cdi-apiserver",
|
||||
UploadProxyImage: "cdi-uploadproxy",
|
||||
UploadServerImage: "cdi-uploadserver",
|
||||
Verbosity: "1",
|
||||
PullPolicy: "Always",
|
||||
Namespace: namespace,
|
||||
}
|
||||
|
||||
return &ReconcileCDI{
|
||||
|
@ -33,13 +33,9 @@ func createAPIServerResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
}
|
||||
|
||||
func createAPIServerClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
return createClusterRoleBinding(apiServerResourceName, apiServerResourceName, apiServerResourceName, namespace)
|
||||
}
|
||||
|
||||
func createAPIServerClusterRole() *rbacv1.ClusterRole {
|
||||
clusterRole := createClusterRole(apiServerResourceName)
|
||||
clusterRole.Rules = []rbacv1.PolicyRule{
|
||||
//GetAPIServerClusterRolePermissions generates permissions for operator
|
||||
func GetAPIServerClusterRolePermissions() []rbacv1.PolicyRule {
|
||||
return []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{
|
||||
"admissionregistration.k8s.io",
|
||||
@ -91,9 +87,18 @@ func createAPIServerClusterRole() *rbacv1.ClusterRole {
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createAPIServerClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
return CreateClusterRoleBinding(apiServerResourceName, apiServerResourceName, apiServerResourceName, namespace)
|
||||
}
|
||||
|
||||
func createAPIServerClusterRole() *rbacv1.ClusterRole {
|
||||
clusterRole := CreateClusterRole(apiServerResourceName)
|
||||
clusterRole.Rules = GetAPIServerClusterRolePermissions()
|
||||
return clusterRole
|
||||
}
|
||||
|
||||
func createAPIServerAuthClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
return createClusterRoleBinding("cdi-apiserver-auth-delegator", "system:auth-delegator", apiServerResourceName, namespace)
|
||||
return CreateClusterRoleBinding("cdi-apiserver-auth-delegator", "system:auth-delegator", apiServerResourceName, namespace)
|
||||
}
|
||||
|
@ -34,12 +34,12 @@ func createControllerResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
|
||||
func createControllerClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
return createClusterRoleBinding(controllerServiceAccountName, controlerClusterRoleName, controllerServiceAccountName, namespace)
|
||||
return CreateClusterRoleBinding(controllerServiceAccountName, controlerClusterRoleName, controllerServiceAccountName, namespace)
|
||||
}
|
||||
|
||||
func createControllerClusterRole() *rbacv1.ClusterRole {
|
||||
clusterRole := createClusterRole(controlerClusterRoleName)
|
||||
clusterRole.Rules = []rbacv1.PolicyRule{
|
||||
//GetControllerPermissions geberates rules for cdi controller
|
||||
func GetControllerPermissions() []rbacv1.PolicyRule {
|
||||
return []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
@ -189,5 +189,10 @@ func createControllerClusterRole() *rbacv1.ClusterRole {
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createControllerClusterRole() *rbacv1.ClusterRole {
|
||||
clusterRole := CreateClusterRole(controlerClusterRoleName)
|
||||
clusterRole.Rules = GetControllerPermissions()
|
||||
return clusterRole
|
||||
}
|
||||
|
@ -24,15 +24,48 @@ import (
|
||||
|
||||
// FactoryArgs contains the required parameters to generate all cluster-scoped resources
|
||||
type FactoryArgs struct {
|
||||
Namespace string
|
||||
DockerRepo string `required:"true" split_words:"true"`
|
||||
DockerTag string `required:"true" split_words:"true"`
|
||||
DeployClusterResources string `required:"true" split_words:"true"`
|
||||
ControllerImage string `required:"true" split_words:"true"`
|
||||
ImporterImage string `required:"true" split_words:"true"`
|
||||
ClonerImage string `required:"true" split_words:"true"`
|
||||
APIServerImage string `required:"true" envconfig:"apiserver_image"`
|
||||
UploadProxyImage string `required:"true" split_words:"true"`
|
||||
UploadServerImage string `required:"true" split_words:"true"`
|
||||
Verbosity string `required:"true"`
|
||||
PullPolicy string `required:"true" split_words:"true"`
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type factoryFunc func(*FactoryArgs) []runtime.Object
|
||||
|
||||
const (
|
||||
//CdiRBAC - groupCode to generate only operator rbac manifest
|
||||
CdiRBAC string = "cdi-rbac"
|
||||
//APIServerRBAC - groupCode to generate only apiserver rbac manifest
|
||||
APIServerRBAC string = "apiserver-rbac"
|
||||
//ControllerRBAC - groupCode to generate only controller rbac manifest
|
||||
ControllerRBAC string = "controller-rbac"
|
||||
//CRDResources - groupCode to generate only resources' manifest
|
||||
CRDResources string = "crd-resources"
|
||||
)
|
||||
|
||||
var factoryFunctions = map[string]factoryFunc{
|
||||
"crd": createCRDResources,
|
||||
"controller": createControllerResources,
|
||||
"apiserver": createAPIServerResources,
|
||||
CdiRBAC: createCdiRBAC,
|
||||
APIServerRBAC: createAPIServerResources,
|
||||
ControllerRBAC: createControllerResources,
|
||||
CRDResources: createCRDResources,
|
||||
}
|
||||
|
||||
//IsFactoryResource returns true id codeGroupo belolngs to factory functions
|
||||
func IsFactoryResource(codeGroup string) bool {
|
||||
for k := range factoryFunctions {
|
||||
if codeGroup == k {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func createCRDResources(args *FactoryArgs) []runtime.Object {
|
||||
@ -42,6 +75,12 @@ func createCRDResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
}
|
||||
|
||||
func createCdiRBAC(args *FactoryArgs) []runtime.Object {
|
||||
return append(
|
||||
createAPIServerResources(args),
|
||||
createControllerResources(args)...)
|
||||
}
|
||||
|
||||
// CreateAllResources creates all cluster-wide resources
|
||||
func CreateAllResources(args *FactoryArgs) ([]runtime.Object, error) {
|
||||
var resources []runtime.Object
|
||||
|
@ -21,7 +21,8 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func createClusterRoleBinding(name, roleRef, serviceAccount, serviceAccountNamespace string) *rbacv1.ClusterRoleBinding {
|
||||
//CreateClusterRoleBinding create cluster role bunding
|
||||
func CreateClusterRoleBinding(name, roleRef, serviceAccount, serviceAccountNamespace string) *rbacv1.ClusterRoleBinding {
|
||||
return &rbacv1.ClusterRoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
@ -48,7 +49,8 @@ func createClusterRoleBinding(name, roleRef, serviceAccount, serviceAccountNames
|
||||
}
|
||||
}
|
||||
|
||||
func createClusterRole(name string) *rbacv1.ClusterRole {
|
||||
//CreateClusterRole create cluster role
|
||||
func CreateClusterRole(name string) *rbacv1.ClusterRole {
|
||||
return &rbacv1.ClusterRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
|
@ -22,6 +22,8 @@ import (
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"kubevirt.io/containerized-data-importer/pkg/common"
|
||||
utils "kubevirt.io/containerized-data-importer/pkg/operator/resources/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -30,6 +32,10 @@ const (
|
||||
extensionAPIConfigMapName = "extension-apiserver-authentication"
|
||||
)
|
||||
|
||||
const (
|
||||
cdiLabel = common.CDIComponentLabel
|
||||
)
|
||||
|
||||
func createAPIServerResources(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createAPIServerServiceAccount(),
|
||||
@ -43,15 +49,15 @@ func createAPIServerResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
|
||||
func createAPIServerServiceAccount() *corev1.ServiceAccount {
|
||||
return createServiceAccount(apiServerRessouceName)
|
||||
return utils.CreateServiceAccount(apiServerRessouceName)
|
||||
}
|
||||
|
||||
func createAPIServerRoleBinding(serviceAccountNamespace string) *rbacv1.RoleBinding {
|
||||
return createRoleBinding(apiServerRessouceName, apiServerRessouceName, apiServerRessouceName, serviceAccountNamespace)
|
||||
return utils.CreateRoleBinding(apiServerRessouceName, apiServerRessouceName, apiServerRessouceName, serviceAccountNamespace)
|
||||
}
|
||||
|
||||
func createAPIServerRole() *rbacv1.Role {
|
||||
role := createRole(apiServerRessouceName)
|
||||
role := utils.CreateRole(apiServerRessouceName)
|
||||
role.Rules = []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{
|
||||
@ -71,7 +77,7 @@ func createAPIServerRole() *rbacv1.Role {
|
||||
}
|
||||
|
||||
func createExtensionAPIServerRoleBinding(serviceAccountNamespace string) *rbacv1.RoleBinding {
|
||||
roleBinding := createRoleBinding(
|
||||
roleBinding := utils.CreateRoleBinding(
|
||||
extensionAPIResourceName,
|
||||
extensionAPIResourceName,
|
||||
apiServerRessouceName,
|
||||
@ -82,7 +88,7 @@ func createExtensionAPIServerRoleBinding(serviceAccountNamespace string) *rbacv1
|
||||
}
|
||||
|
||||
func createExtensionAPIServerRole() *rbacv1.Role {
|
||||
role := createRole(extensionAPIResourceName)
|
||||
role := utils.CreateRole(extensionAPIResourceName)
|
||||
role.Rules = []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{
|
||||
@ -104,7 +110,7 @@ func createExtensionAPIServerRole() *rbacv1.Role {
|
||||
}
|
||||
|
||||
func createAPIServerService() *corev1.Service {
|
||||
service := createService("cdi-api", cdiLabel, apiServerRessouceName)
|
||||
service := utils.CreateService("cdi-api", cdiLabel, apiServerRessouceName)
|
||||
service.Spec.Ports = []corev1.ServicePort{
|
||||
{
|
||||
Port: 443,
|
||||
@ -119,8 +125,8 @@ func createAPIServerService() *corev1.Service {
|
||||
}
|
||||
|
||||
func createAPIServerDeployment(repo, image, tag, verbosity, pullPolicy string) *appsv1.Deployment {
|
||||
deployment := createDeployment(apiServerRessouceName, cdiLabel, apiServerRessouceName, apiServerRessouceName, 1)
|
||||
container := createContainer(apiServerRessouceName, repo, image, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
deployment := utils.CreateDeployment(apiServerRessouceName, cdiLabel, apiServerRessouceName, apiServerRessouceName, 1)
|
||||
container := utils.CreateContainer(apiServerRessouceName, repo, image, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
container.ReadinessProbe = &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 The CDI Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package namespaced
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"kubevirt.io/containerized-data-importer/pkg/common"
|
||||
)
|
||||
|
||||
const (
|
||||
cdiLabel = common.CDIComponentLabel
|
||||
)
|
||||
|
||||
var commonLabels = map[string]string{
|
||||
"cdi.kubevirt.io": "",
|
||||
}
|
||||
|
||||
func withCommonLabels(labels map[string]string) map[string]string {
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
}
|
||||
|
||||
for k, v := range commonLabels {
|
||||
_, ok := labels[k]
|
||||
if !ok {
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func createServiceAccount(name string) *corev1.ServiceAccount {
|
||||
return &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: withCommonLabels(nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createRoleBinding(name, roleRef, serviceAccount, serviceAccountNamespace string) *rbacv1.RoleBinding {
|
||||
return &rbacv1.RoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
Kind: "RoleBinding",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: withCommonLabels(nil),
|
||||
},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: roleRef,
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: serviceAccount,
|
||||
Namespace: serviceAccountNamespace,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createRole(name string) *rbacv1.Role {
|
||||
return &rbacv1.Role{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
Kind: "Role",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: withCommonLabels(nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createDeployment(name, matchKey, matchValue, serviceAccount string, numReplicas int32) *appsv1.Deployment {
|
||||
matchMap := map[string]string{matchKey: matchValue}
|
||||
deployment := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: withCommonLabels(matchMap),
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Replicas: &numReplicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
matchKey: matchValue,
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: withCommonLabels(matchMap),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if serviceAccount != "" {
|
||||
deployment.Spec.Template.Spec.ServiceAccountName = serviceAccount
|
||||
}
|
||||
return deployment
|
||||
}
|
||||
|
||||
func createContainer(name, repo, image, tag, verbosity string, pullPolicy corev1.PullPolicy) corev1.Container {
|
||||
return corev1.Container{
|
||||
Name: name,
|
||||
Image: fmt.Sprintf("%s/%s:%s", repo, image, tag),
|
||||
ImagePullPolicy: pullPolicy,
|
||||
Args: []string{"-v=" + verbosity},
|
||||
}
|
||||
}
|
||||
|
||||
func createService(name, matchKey, matchValue string) *corev1.Service {
|
||||
matchMap := map[string]string{matchKey: matchValue}
|
||||
return &corev1.Service{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Service",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: withCommonLabels(matchMap),
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Selector: matchMap,
|
||||
},
|
||||
}
|
||||
}
|
@ -26,6 +26,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"kubevirt.io/containerized-data-importer/pkg/common"
|
||||
|
||||
utils "kubevirt.io/containerized-data-importer/pkg/operator/resources/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -56,12 +58,12 @@ func createControllerResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
|
||||
func createControllerServiceAccount() *corev1.ServiceAccount {
|
||||
return createServiceAccount(controllerServiceAccount)
|
||||
return utils.CreateServiceAccount(controllerServiceAccount)
|
||||
}
|
||||
|
||||
func createControllerDeployment(repo, controllerImage, importerImage, clonerImage, uploadServerImage, tag, verbosity, pullPolicy string) *appsv1.Deployment {
|
||||
deployment := createDeployment("cdi-deployment", "app", "containerized-data-importer", controllerServiceAccount, int32(1))
|
||||
container := createContainer("cdi-controller", repo, controllerImage, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
deployment := utils.CreateDeployment("cdi-deployment", "app", "containerized-data-importer", controllerServiceAccount, int32(1))
|
||||
container := utils.CreateContainer("cdi-controller", repo, controllerImage, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
container.Env = []corev1.EnvVar{
|
||||
{
|
||||
Name: "IMPORTER_IMAGE",
|
||||
@ -137,7 +139,7 @@ func createInsecureRegConfigMap() *corev1.ConfigMap {
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.InsecureRegistryConfigMap,
|
||||
Labels: withCommonLabels(nil),
|
||||
Labels: utils.WithCommonLabels(nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -24,17 +24,18 @@ import (
|
||||
|
||||
// FactoryArgs contains the required parameters to generate all namespaced resources
|
||||
type FactoryArgs struct {
|
||||
DockerRepo string `required:"true" split_words:"true"`
|
||||
DockerTag string `required:"true" split_words:"true"`
|
||||
ControllerImage string `required:"true" split_words:"true"`
|
||||
ImporterImage string `required:"true" split_words:"true"`
|
||||
ClonerImage string `required:"true" split_words:"true"`
|
||||
APIServerImage string `required:"true" envconfig:"apiserver_image"`
|
||||
UploadProxyImage string `required:"true" split_words:"true"`
|
||||
UploadServerImage string `required:"true" split_words:"true"`
|
||||
Verbosity string `required:"true"`
|
||||
PullPolicy string `required:"true" split_words:"true"`
|
||||
Namespace string
|
||||
DockerRepo string `required:"true" split_words:"true"`
|
||||
DockerTag string `required:"true" split_words:"true"`
|
||||
ControllerImage string `required:"true" split_words:"true"`
|
||||
DeployClusterResources string `required:"true" split_words:"true"`
|
||||
ImporterImage string `required:"true" split_words:"true"`
|
||||
ClonerImage string `required:"true" split_words:"true"`
|
||||
APIServerImage string `required:"true" envconfig:"apiserver_image"`
|
||||
UploadProxyImage string `required:"true" split_words:"true"`
|
||||
UploadServerImage string `required:"true" split_words:"true"`
|
||||
Verbosity string `required:"true"`
|
||||
PullPolicy string `required:"true" split_words:"true"`
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type factoryFunc func(*FactoryArgs) []runtime.Object
|
||||
@ -50,6 +51,16 @@ var factoryFunctions = map[string]factoryFunc{
|
||||
"uploadproxy": createUploadProxyResources,
|
||||
}
|
||||
|
||||
//IsFactoryResource returns true id codeGroupo belolngs to factory functions
|
||||
func IsFactoryResource(codeGroup string) bool {
|
||||
for k := range factoryFunctions {
|
||||
if codeGroup == k {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetPrivilegedAccounts return special accounts for OpenShift
|
||||
// TODO should prob break this up into groups like the rest of this stuff
|
||||
func GetPrivilegedAccounts(args *FactoryArgs) []string {
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
utils "kubevirt.io/containerized-data-importer/pkg/operator/resources/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,7 +36,7 @@ func createUploadProxyResources(args *FactoryArgs) []runtime.Object {
|
||||
}
|
||||
|
||||
func createUploadProxyService() *corev1.Service {
|
||||
service := createService(uploadProxyResourceName, cdiLabel, uploadProxyResourceName)
|
||||
service := utils.CreateService(uploadProxyResourceName, cdiLabel, uploadProxyResourceName)
|
||||
service.Spec.Ports = []corev1.ServicePort{
|
||||
{
|
||||
Port: 443,
|
||||
@ -50,8 +51,8 @@ func createUploadProxyService() *corev1.Service {
|
||||
}
|
||||
|
||||
func createUploadProxyDeployment(repo, image, tag, verbosity, pullPolicy string) *appsv1.Deployment {
|
||||
deployment := createDeployment(uploadProxyResourceName, cdiLabel, uploadProxyResourceName, "", int32(1))
|
||||
container := createContainer(uploadProxyResourceName, repo, image, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
deployment := utils.CreateDeployment(uploadProxyResourceName, cdiLabel, uploadProxyResourceName, "", int32(1))
|
||||
container := utils.CreateContainer(uploadProxyResourceName, repo, image, tag, verbosity, corev1.PullPolicy(pullPolicy))
|
||||
container.Env = []corev1.EnvVar{
|
||||
{
|
||||
Name: "APISERVER_PUBLIC_KEY",
|
||||
|
103
pkg/operator/resources/operator/components.go
Normal file
103
pkg/operator/resources/operator/components.go
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright 2018 The CDI Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
)
|
||||
|
||||
const (
|
||||
//ControllerImageDefault - defualt value
|
||||
ControllerImageDefault = "cdi-controller"
|
||||
//ImporterImageDefault - defualt value
|
||||
ImporterImageDefault = "cdi-importer"
|
||||
//ClonerImageDefault - defualt value
|
||||
ClonerImageDefault = "cdi-cloner"
|
||||
//APIServerImageDefault - defualt value
|
||||
APIServerImageDefault = "cdi-apiserver"
|
||||
//UploadProxyImageDefault - defualt value
|
||||
UploadProxyImageDefault = "cdi-uploadproxy"
|
||||
//UploadServerImageDefault - defualt value
|
||||
UploadServerImageDefault = "cdi-uploadserver"
|
||||
)
|
||||
|
||||
//CdiImages - images to be provied to cdi operator
|
||||
type CdiImages struct {
|
||||
ControllerImage string
|
||||
ImporterImage string
|
||||
ClonerImage string
|
||||
APIServerImage string
|
||||
UplodaProxyImage string
|
||||
UplodaServerImage string
|
||||
}
|
||||
|
||||
//FillDefaults - fill image names with defaults
|
||||
func (ci *CdiImages) FillDefaults() *CdiImages {
|
||||
if ci.ControllerImage == "" {
|
||||
ci.ControllerImage = ControllerImageDefault
|
||||
}
|
||||
if ci.ImporterImage == "" {
|
||||
ci.ImporterImage = ImporterImageDefault
|
||||
}
|
||||
if ci.ClonerImage == "" {
|
||||
ci.ClonerImage = ClonerImageDefault
|
||||
}
|
||||
if ci.APIServerImage == "" {
|
||||
ci.ClonerImage = APIServerImageDefault
|
||||
}
|
||||
if ci.UplodaProxyImage == "" {
|
||||
ci.ClonerImage = UploadProxyImageDefault
|
||||
}
|
||||
if ci.UplodaServerImage == "" {
|
||||
ci.ClonerImage = UploadServerImageDefault
|
||||
}
|
||||
|
||||
return ci
|
||||
}
|
||||
|
||||
//NewCdiOperatorDeployment - provides operator deployment spec
|
||||
func NewCdiOperatorDeployment(namespace string, repository string, tag string, imagePullPolicy string, verbosity string, cdiImages *CdiImages) (*appsv1.Deployment, error) {
|
||||
name := "cdi-operator"
|
||||
deployment := createOperatorDeployment(
|
||||
repository,
|
||||
namespace,
|
||||
"true",
|
||||
name,
|
||||
cdiImages.ControllerImage,
|
||||
cdiImages.ImporterImage,
|
||||
cdiImages.ClonerImage,
|
||||
cdiImages.APIServerImage,
|
||||
cdiImages.UplodaProxyImage,
|
||||
cdiImages.UplodaServerImage,
|
||||
tag,
|
||||
verbosity,
|
||||
imagePullPolicy)
|
||||
|
||||
return deployment, nil
|
||||
}
|
||||
|
||||
//NewCdiOperatorClusterRole - provides operator clusterRole
|
||||
func NewCdiOperatorClusterRole() *rbacv1.ClusterRole {
|
||||
return createOperatorClusterRole(operatorClusterRoleName)
|
||||
}
|
||||
|
||||
//NewCdiCrd - provides CDI CRD
|
||||
func NewCdiCrd() *extv1beta1.CustomResourceDefinition {
|
||||
return createCDIListCRD()
|
||||
}
|
116
pkg/operator/resources/operator/factory.go
Normal file
116
pkg/operator/resources/operator/factory.go
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright 2018 The CDI Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
//FactoryArgs contains the required parameters to generate all cluster-scoped resources
|
||||
type FactoryArgs struct {
|
||||
OperatorImage string `required:"true" split_words:"true"`
|
||||
DockerRepo string `required:"true" split_words:"true"`
|
||||
DockerTag string `required:"true" split_words:"true"`
|
||||
DeployClusterResources string `required:"true" split_words:"true"`
|
||||
ControllerImage string `required:"true" split_words:"true"`
|
||||
ImporterImage string `required:"true" split_words:"true"`
|
||||
ClonerImage string `required:"true" split_words:"true"`
|
||||
APIServerImage string `required:"true" envconfig:"apiserver_image"`
|
||||
UploadProxyImage string `required:"true" split_words:"true"`
|
||||
UploadServerImage string `required:"true" split_words:"true"`
|
||||
Verbosity string `required:"true"`
|
||||
PullPolicy string `required:"true" split_words:"true"`
|
||||
Namespace string
|
||||
}
|
||||
|
||||
type operatorFactoryFunc func(*FactoryArgs) []runtime.Object
|
||||
|
||||
const (
|
||||
//OperatorRBAC - operator rbac
|
||||
OperatorRBAC string = "operator-rbac"
|
||||
//OperatorDeployment - operator deployment
|
||||
OperatorDeployment string = "operator-deployment"
|
||||
//OperatorCdiCRD - operator CRDs
|
||||
OperatorCdiCRD string = "operator-cdi-crd"
|
||||
//OperatorConfigMapCR - operartor configmap
|
||||
OperatorConfigMapCR string = "operator-configmap-cr"
|
||||
)
|
||||
|
||||
var operatorFactoryFunctions = map[string]operatorFactoryFunc{
|
||||
OperatorRBAC: createOperatorClusterRBAC,
|
||||
OperatorDeployment: createOperatorClusterDeployment,
|
||||
OperatorCdiCRD: createOperatorCDIClusterResource,
|
||||
OperatorConfigMapCR: createOperatorConfigMapClusterResource,
|
||||
}
|
||||
|
||||
//IsFactoryResource returns true id codeGroupo belolngs to factory functions
|
||||
func IsFactoryResource(codeGroup string) bool {
|
||||
for k := range operatorFactoryFunctions {
|
||||
if codeGroup == k {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//GetOperatorClusterRules returnes operator cluster rules
|
||||
func GetOperatorClusterRules() *[]rbacv1.PolicyRule {
|
||||
return getOperatorClusterRules()
|
||||
}
|
||||
|
||||
//GetOperatorDeploymentSpec returns operator deployment spce
|
||||
func GetOperatorDeploymentSpec(args *FactoryArgs) *appsv1.DeploymentSpec {
|
||||
return createOperatorDeploymentSpec(args.DockerRepo,
|
||||
args.Namespace,
|
||||
args.DeployClusterResources,
|
||||
args.OperatorImage,
|
||||
args.ControllerImage,
|
||||
args.ImporterImage,
|
||||
args.ClonerImage,
|
||||
args.APIServerImage,
|
||||
args.UploadProxyImage,
|
||||
args.UploadServerImage,
|
||||
args.DockerTag,
|
||||
args.Verbosity,
|
||||
args.PullPolicy)
|
||||
}
|
||||
|
||||
// CreateAllOperatorResources creates all cluster-wide resources
|
||||
func CreateAllOperatorResources(args *FactoryArgs) ([]runtime.Object, error) {
|
||||
var resources []runtime.Object
|
||||
for group := range operatorFactoryFunctions {
|
||||
rs, err := CreateOperatorResourceGroup(group, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resources = append(resources, rs...)
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// CreateOperatorResourceGroup creates all cluster resources fr a specific group/component
|
||||
func CreateOperatorResourceGroup(group string, args *FactoryArgs) ([]runtime.Object, error) {
|
||||
f, ok := operatorFactoryFunctions[group]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Group %s does not exist", group)
|
||||
}
|
||||
return f(args), nil
|
||||
}
|
532
pkg/operator/resources/operator/operator.go
Normal file
532
pkg/operator/resources/operator/operator.go
Normal file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
Copyright 2018 The CDI Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package operator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"kubevirt.io/containerized-data-importer/pkg/common"
|
||||
cluster "kubevirt.io/containerized-data-importer/pkg/operator/resources/cluster"
|
||||
utils "kubevirt.io/containerized-data-importer/pkg/operator/resources/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
operatorServiceAccountName = "cdi-operator"
|
||||
operatorClusterRoleName = "cdi-operator-cluster-role"
|
||||
operatorNamespacedRoleName = "cdi-operator-role"
|
||||
privilegedAccountPrefix = "system:serviceaccount"
|
||||
prometheusLabel = common.PrometheusLabel
|
||||
)
|
||||
|
||||
func createOperatorResources(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createCDIListCRD(),
|
||||
createOperatorServiceAccount(args.Namespace),
|
||||
createOperatorClusterRole(operatorClusterRoleName),
|
||||
createOperatorClusterRoleBinding(args.Namespace),
|
||||
createOperatorLeaderElectionConfigMap(args.Namespace),
|
||||
createOperatorDeployment(args.DockerRepo,
|
||||
args.Namespace,
|
||||
args.DeployClusterResources,
|
||||
args.OperatorImage,
|
||||
args.ControllerImage,
|
||||
args.ImporterImage,
|
||||
args.ClonerImage,
|
||||
args.APIServerImage,
|
||||
args.UploadProxyImage,
|
||||
args.UploadServerImage,
|
||||
args.DockerTag,
|
||||
args.Verbosity,
|
||||
args.PullPolicy),
|
||||
}
|
||||
}
|
||||
|
||||
func getOperatorClusterRules() *[]rbacv1.PolicyRule {
|
||||
rules := []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{
|
||||
"rbac.authorization.k8s.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"roles",
|
||||
"rolebindings",
|
||||
"clusterrolebindings",
|
||||
"clusterroles",
|
||||
},
|
||||
Verbs: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"security.openshift.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"securitycontextconstraints",
|
||||
},
|
||||
Verbs: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"serviceaccounts",
|
||||
"services",
|
||||
},
|
||||
Verbs: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"nodes",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
"update",
|
||||
"patch",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"extensions",
|
||||
},
|
||||
Resources: []string{
|
||||
"deployments",
|
||||
},
|
||||
Verbs: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"extensions",
|
||||
},
|
||||
Resources: []string{
|
||||
"ingresses",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"configmaps",
|
||||
},
|
||||
Verbs: []string{
|
||||
"watch",
|
||||
"create",
|
||||
"delete",
|
||||
"get",
|
||||
"update",
|
||||
"patch",
|
||||
"list",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"batch",
|
||||
},
|
||||
Resources: []string{
|
||||
"jobs",
|
||||
},
|
||||
Verbs: []string{
|
||||
"create",
|
||||
"delete",
|
||||
"get",
|
||||
"update",
|
||||
"patch",
|
||||
"list",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"apiextensions.k8s.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"customresourcedefinitions",
|
||||
},
|
||||
Verbs: []string{
|
||||
"create",
|
||||
"delete",
|
||||
"get",
|
||||
"update",
|
||||
"patch",
|
||||
"list",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"apps",
|
||||
},
|
||||
Resources: []string{
|
||||
"deployments",
|
||||
"daemonstes",
|
||||
},
|
||||
Verbs: []string{
|
||||
"create",
|
||||
"get",
|
||||
"list",
|
||||
"delete",
|
||||
"watch",
|
||||
"update",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"admissionregistration.k8s.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"validatingwebhookconfigurations",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"create",
|
||||
"update",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"apiregistration.k8s.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"apiservices",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"create",
|
||||
"update",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"cdi.kubevirt.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"*",
|
||||
},
|
||||
Verbs: []string{
|
||||
"*",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"events",
|
||||
},
|
||||
Verbs: []string{
|
||||
"create",
|
||||
"update",
|
||||
"patch",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"pods",
|
||||
"persistentvolumeclaims",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
"create",
|
||||
"update",
|
||||
"patch",
|
||||
"delete",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"persistentvolumeclaims/finalizers",
|
||||
"pods/finalizers",
|
||||
},
|
||||
Verbs: []string{
|
||||
"update",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"services",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
"create",
|
||||
"delete",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"secrets",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
"create",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"",
|
||||
},
|
||||
Resources: []string{
|
||||
"namespaces",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{
|
||||
"route.openshift.io",
|
||||
},
|
||||
Resources: []string{
|
||||
"routes",
|
||||
},
|
||||
Verbs: []string{
|
||||
"get",
|
||||
"list",
|
||||
"watch",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return &rules
|
||||
}
|
||||
|
||||
func createOperatorClusterRole(roleName string) *rbacv1.ClusterRole {
|
||||
clusterRole := cluster.CreateClusterRole(roleName)
|
||||
clusterRole.Rules = *getOperatorClusterRules()
|
||||
|
||||
return clusterRole
|
||||
}
|
||||
|
||||
func createOperatorClusterRBAC(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createOperatorServiceAccount(args.Namespace),
|
||||
createOperatorClusterRole(operatorClusterRoleName),
|
||||
createOperatorClusterRoleBinding(args.Namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorClusterDeployment(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createOperatorDeployment(args.DockerRepo,
|
||||
args.Namespace,
|
||||
args.DeployClusterResources,
|
||||
args.OperatorImage,
|
||||
args.ControllerImage,
|
||||
args.ImporterImage,
|
||||
args.ClonerImage,
|
||||
args.APIServerImage,
|
||||
args.UploadProxyImage,
|
||||
args.UploadServerImage,
|
||||
args.DockerTag,
|
||||
args.Verbosity,
|
||||
args.PullPolicy)}
|
||||
}
|
||||
|
||||
func createOperatorClusterResources(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createCDIListCRD(),
|
||||
createOperatorLeaderElectionConfigMap(args.Namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorCDIClusterResource(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createCDIListCRD(),
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorConfigMapClusterResource(args *FactoryArgs) []runtime.Object {
|
||||
return []runtime.Object{
|
||||
createOperatorLeaderElectionConfigMap(args.Namespace),
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
return cluster.CreateClusterRoleBinding(operatorServiceAccountName, operatorClusterRoleName, operatorServiceAccountName, namespace)
|
||||
}
|
||||
|
||||
func getOperatorPrivilegedAccounts(args *FactoryArgs) []string {
|
||||
return []string{
|
||||
fmt.Sprintf("%s:%s:%s", privilegedAccountPrefix, args.Namespace, operatorServiceAccountName),
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorServiceAccount(namespace string) *corev1.ServiceAccount {
|
||||
return utils.CreateServiceNamespaceAccount(operatorServiceAccountName, namespace)
|
||||
}
|
||||
|
||||
func createOperatorLeaderElectionConfigMap(namespace string) *corev1.ConfigMap {
|
||||
return &corev1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cdi-operator-leader-election-helper",
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{
|
||||
"operator.cdi.kubevirt.io": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func createCDIListCRD() *extv1beta1.CustomResourceDefinition {
|
||||
return &extv1beta1.CustomResourceDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apiextensions.k8s.io/v1beta1",
|
||||
Kind: "CustomResourceDefinition",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cdis.cdi.kubevirt.io",
|
||||
Labels: map[string]string{
|
||||
"operator.cdi.kubevirt.io": "",
|
||||
},
|
||||
},
|
||||
Spec: extv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: "cdi.kubevirt.io",
|
||||
Names: extv1beta1.CustomResourceDefinitionNames{
|
||||
Kind: "CDI",
|
||||
ListKind: "CDIList",
|
||||
Plural: "cdis",
|
||||
Singular: "cdi",
|
||||
},
|
||||
Version: "v1alpha1",
|
||||
Scope: "Cluster",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
uploadProxyResourceName = "cdi-uploadproxy"
|
||||
)
|
||||
|
||||
func createOperatorDeploymentSpec(repo, namespace, deployClusterResources, operatorImage, controllerImage, importerImage, clonerImage, apiServerImage, uploadProxyImage, uploadServerImage, tag, verbosity, pullPolicy string) *appsv1.DeploymentSpec {
|
||||
spec := utils.CreateOperatorDeploymentSpec("cdi-operator", namespace, "name", "cdi-operator", operatorServiceAccountName, int32(1))
|
||||
container := utils.CreatePortsContainer("cdi-operator", repo, operatorImage, tag, verbosity, corev1.PullPolicy(pullPolicy), createPrometheusPorts())
|
||||
container.Env = *createOperatorEnvVar(repo, deployClusterResources, operatorImage, controllerImage, importerImage, clonerImage, apiServerImage, uploadProxyImage, uploadServerImage, tag, verbosity, pullPolicy)
|
||||
spec.Template.Spec.Containers = []corev1.Container{container}
|
||||
return spec
|
||||
}
|
||||
|
||||
func createOperatorEnvVar(repo, deployClusterResources, operatorImage, controllerImage, importerImage, clonerImage, apiServerImage, uploadProxyImage, uploadServerImage, tag, verbosity, pullPolicy string) *[]corev1.EnvVar {
|
||||
return &[]corev1.EnvVar{
|
||||
{
|
||||
Name: "DEPLOY_CLUSTER_RESOURCES",
|
||||
Value: fmt.Sprintf("%s", deployClusterResources),
|
||||
},
|
||||
{
|
||||
Name: "DOCKER_REPO",
|
||||
Value: fmt.Sprintf("%s", repo),
|
||||
},
|
||||
{
|
||||
Name: "DOCKER_TAG",
|
||||
Value: fmt.Sprintf("%s", tag),
|
||||
},
|
||||
{
|
||||
Name: "CONTROLLER_IMAGE",
|
||||
Value: fmt.Sprintf("%s", controllerImage),
|
||||
},
|
||||
{
|
||||
Name: "IMPORTER_IMAGE",
|
||||
Value: fmt.Sprintf("%s", importerImage),
|
||||
},
|
||||
{
|
||||
Name: "CLONER_IMAGE",
|
||||
Value: fmt.Sprintf("%s", clonerImage),
|
||||
},
|
||||
{
|
||||
Name: "APISERVER_IMAGE",
|
||||
Value: fmt.Sprintf("%s", apiServerImage),
|
||||
},
|
||||
{
|
||||
Name: "UPLOAD_SERVER_IMAGE",
|
||||
Value: fmt.Sprintf("%s", uploadServerImage),
|
||||
},
|
||||
{
|
||||
Name: "UPLOAD_PROXY_IMAGE",
|
||||
Value: fmt.Sprintf("%s", uploadProxyImage),
|
||||
},
|
||||
{
|
||||
Name: "VERBOSITY",
|
||||
Value: verbosity,
|
||||
},
|
||||
{
|
||||
Name: "PULL_POLICY",
|
||||
Value: pullPolicy,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createOperatorDeployment(repo, namespace, deployClusterResources, operatorImage, controllerImage, importerImage, clonerImage, apiServerImage, uploadProxyImage, uploadServerImage, tag, verbosity, pullPolicy string) *appsv1.Deployment {
|
||||
deployment := utils.CreateOperatorDeployment("cdi-operator", namespace, "name", "cdi-operator", operatorServiceAccountName, int32(1))
|
||||
container := utils.CreatePortsContainer("cdi-operator", repo, operatorImage, tag, verbosity, corev1.PullPolicy(pullPolicy), createPrometheusPorts())
|
||||
container.Env = *createOperatorEnvVar(repo, deployClusterResources, operatorImage, controllerImage, importerImage, clonerImage, apiServerImage, uploadProxyImage, uploadServerImage, tag, verbosity, pullPolicy)
|
||||
deployment.Spec.Template.Spec.Containers = []corev1.Container{container}
|
||||
return deployment
|
||||
}
|
||||
|
||||
func createPrometheusPorts() *[]corev1.ContainerPort {
|
||||
return &[]corev1.ContainerPort{
|
||||
{
|
||||
Name: "metrics",
|
||||
ContainerPort: 60000,
|
||||
},
|
||||
}
|
||||
}
|
259
pkg/operator/resources/utils/common.go
Normal file
259
pkg/operator/resources/utils/common.go
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
Copyright 2018 The CDI Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"kubevirt.io/containerized-data-importer/pkg/common"
|
||||
)
|
||||
|
||||
const (
|
||||
cdiLabel = common.CDIComponentLabel
|
||||
)
|
||||
|
||||
var commonLabels = map[string]string{
|
||||
"cdi.kubevirt.io": "",
|
||||
}
|
||||
|
||||
var operatorLabels = map[string]string{
|
||||
"operator.cdi.kubevirt.io": "",
|
||||
}
|
||||
|
||||
//WithCommonLabels aggregates common lables
|
||||
func WithCommonLabels(labels map[string]string) map[string]string {
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
}
|
||||
|
||||
for k, v := range commonLabels {
|
||||
_, ok := labels[k]
|
||||
if !ok {
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
//WithOperatorLabels aggregates common lables
|
||||
func WithOperatorLabels(labels map[string]string) map[string]string {
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
}
|
||||
|
||||
for k, v := range operatorLabels {
|
||||
_, ok := labels[k]
|
||||
if !ok {
|
||||
labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
//CreateServiceAccount creates service account
|
||||
func CreateServiceAccount(name string) *corev1.ServiceAccount {
|
||||
return &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: WithCommonLabels(nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//CreateServiceNamespaceAccount creates service account
|
||||
func CreateServiceNamespaceAccount(name, namespace string) *corev1.ServiceAccount {
|
||||
return &corev1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ServiceAccount",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{
|
||||
"operator.cdi.kubevirt.io": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//CreateRoleBinding creates role binding
|
||||
func CreateRoleBinding(name, roleRef, serviceAccount, serviceAccountNamespace string) *rbacv1.RoleBinding {
|
||||
return &rbacv1.RoleBinding{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
Kind: "RoleBinding",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: WithCommonLabels(nil),
|
||||
},
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "Role",
|
||||
Name: roleRef,
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
},
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Name: serviceAccount,
|
||||
Namespace: serviceAccountNamespace,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//CreateRole creates role
|
||||
func CreateRole(name string) *rbacv1.Role {
|
||||
return &rbacv1.Role{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
Kind: "Role",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: WithCommonLabels(nil),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//CreateOperatorDeploymentSpec creates deployment
|
||||
func CreateOperatorDeploymentSpec(name, namespace, matchKey, matchValue, serviceAccount string, numReplicas int32) *appsv1.DeploymentSpec {
|
||||
spec := &appsv1.DeploymentSpec{
|
||||
Replicas: &numReplicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"name": "cdi-operator",
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"name": "cdi-operator"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if serviceAccount != "" {
|
||||
spec.Template.Spec.ServiceAccountName = serviceAccount
|
||||
}
|
||||
|
||||
return spec
|
||||
}
|
||||
|
||||
//CreateOperatorDeployment creates deployment
|
||||
func CreateOperatorDeployment(name, namespace, matchKey, matchValue, serviceAccount string, numReplicas int32) *appsv1.Deployment {
|
||||
//matchMap := map[string]string{matchKey: matchValue}
|
||||
deployment := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"operator.cdi.kubevirt.io": "",
|
||||
},
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: *CreateOperatorDeploymentSpec(name, namespace, matchKey, matchValue, serviceAccount, numReplicas),
|
||||
}
|
||||
if serviceAccount != "" {
|
||||
deployment.Spec.Template.Spec.ServiceAccountName = serviceAccount
|
||||
}
|
||||
return deployment
|
||||
}
|
||||
|
||||
//CreateDeployment creates deployment
|
||||
func CreateDeployment(name, matchKey, matchValue, serviceAccount string, numReplicas int32) *appsv1.Deployment {
|
||||
matchMap := map[string]string{matchKey: matchValue}
|
||||
deployment := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: WithCommonLabels(matchMap),
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Replicas: &numReplicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
matchKey: matchValue,
|
||||
},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: WithCommonLabels(matchMap),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if serviceAccount != "" {
|
||||
deployment.Spec.Template.Spec.ServiceAccountName = serviceAccount
|
||||
}
|
||||
return deployment
|
||||
}
|
||||
|
||||
//CreatePortsContainer creates container
|
||||
func CreatePortsContainer(name, repo, image, tag, verbosity string, pullPolicy corev1.PullPolicy, ports *[]corev1.ContainerPort) corev1.Container {
|
||||
return corev1.Container{
|
||||
Name: name,
|
||||
Image: fmt.Sprintf("%s/%s:%s", repo, image, tag),
|
||||
Ports: *ports,
|
||||
ImagePullPolicy: pullPolicy,
|
||||
}
|
||||
}
|
||||
|
||||
//CreateContainer creates container
|
||||
func CreateContainer(name, repo, image, tag, verbosity string, pullPolicy corev1.PullPolicy) corev1.Container {
|
||||
return corev1.Container{
|
||||
Name: name,
|
||||
Image: fmt.Sprintf("%s/%s:%s", repo, image, tag),
|
||||
ImagePullPolicy: pullPolicy,
|
||||
Args: []string{"-v=" + verbosity},
|
||||
}
|
||||
}
|
||||
|
||||
//CreateService creates service
|
||||
func CreateService(name, matchKey, matchValue string) *corev1.Service {
|
||||
matchMap := map[string]string{matchKey: matchValue}
|
||||
return &corev1.Service{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Service",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: WithCommonLabels(matchMap),
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Selector: matchMap,
|
||||
},
|
||||
}
|
||||
}
|
@ -13,50 +13,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/klog"
|
||||
cdicluster "kubevirt.io/containerized-data-importer/pkg/operator/resources/cluster"
|
||||
"kubevirt.io/containerized-data-importer/pkg/operator/resources/namespaced"
|
||||
cdinamespaced "kubevirt.io/containerized-data-importer/pkg/operator/resources/namespaced"
|
||||
cdioperator "kubevirt.io/containerized-data-importer/pkg/operator/resources/operator"
|
||||
)
|
||||
|
||||
const (
|
||||
initialCsvVersion string = "0.0.0"
|
||||
)
|
||||
|
||||
type templateData struct {
|
||||
DockerRepo string
|
||||
DockerTag string
|
||||
ControllerImage string
|
||||
ImporterImage string
|
||||
ClonerImage string
|
||||
APIServerImage string
|
||||
UploadProxyImage string
|
||||
UploadServerImage string
|
||||
OperatorImage string
|
||||
Verbosity string
|
||||
PullPolicy string
|
||||
Namespace string
|
||||
DockerRepo string
|
||||
DockerTag string
|
||||
CsvVersion string
|
||||
ReplacesCsvVersion string
|
||||
QuayNamespace string
|
||||
QuayRepository string
|
||||
OperatorRules string
|
||||
OperatorDeploymentSpec string
|
||||
CDILogo string
|
||||
DeployClusterResources string
|
||||
OperatorImage string
|
||||
ControllerImage string
|
||||
ImporterImage string
|
||||
ClonerImage string
|
||||
APIServerImage string
|
||||
UploadProxyImage string
|
||||
UploadServerImage string
|
||||
Verbosity string
|
||||
PullPolicy string
|
||||
Namespace string
|
||||
GeneratedManifests map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
dockerRepo = flag.String("docker-repo", "", "")
|
||||
dockertag = flag.String("docker-tag", "", "")
|
||||
controllerImage = flag.String("controller-image", "", "")
|
||||
importerImage = flag.String("importer-image", "", "")
|
||||
clonerImage = flag.String("cloner-image", "", "")
|
||||
apiServerImage = flag.String("apiserver-image", "", "")
|
||||
uploadProxyImage = flag.String("uploadproxy-image", "", "")
|
||||
uploadServerImage = flag.String("uploadserver-image", "", "")
|
||||
operatorImage = flag.String("operator-image", "", "")
|
||||
verbosity = flag.String("verbosity", "1", "")
|
||||
pullPolicy = flag.String("pull-policy", "", "")
|
||||
namespace = flag.String("namespace", "", "")
|
||||
dockerRepo = flag.String("docker-repo", "", "")
|
||||
dockertag = flag.String("docker-tag", "", "")
|
||||
csvVersion = flag.String("csv-version", "", "")
|
||||
cdiLogoPath = flag.String("cdi-logo-path", "", "")
|
||||
genManifestsPath = flag.String("generated-manifests-path", "", "")
|
||||
quayNamespace = flag.String("quay-namespace", "", "")
|
||||
quayRepository = flag.String("quay-repository", "", "")
|
||||
deployClusterResources = flag.String("deploy-cluster-resources", "", "")
|
||||
operatorImage = flag.String("operator-image", "", "")
|
||||
controllerImage = flag.String("controller-image", "", "")
|
||||
importerImage = flag.String("importer-image", "", "")
|
||||
clonerImage = flag.String("cloner-image", "", "")
|
||||
apiServerImage = flag.String("apiserver-image", "", "")
|
||||
uploadProxyImage = flag.String("uploadproxy-image", "", "")
|
||||
uploadServerImage = flag.String("uploadserver-image", "", "")
|
||||
verbosity = flag.String("verbosity", "1", "")
|
||||
pullPolicy = flag.String("pull-policy", "", "")
|
||||
namespace = flag.String("namespace", "", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
templFile := flag.String("template", "", "")
|
||||
codeGroup := flag.String("code-group", "everything", "")
|
||||
flag.Parse()
|
||||
|
||||
klogFlags := flag.NewFlagSet("klog", flag.ExitOnError)
|
||||
klog.InitFlags(klogFlags)
|
||||
flag.CommandLine.VisitAll(func(f1 *flag.Flag) {
|
||||
@ -75,20 +102,86 @@ func main() {
|
||||
generateFromCode(*codeGroup)
|
||||
}
|
||||
|
||||
func getOperatorRules() string {
|
||||
rules := *cdioperator.GetOperatorClusterRules()
|
||||
|
||||
writer := strings.Builder{}
|
||||
for _, rule := range rules {
|
||||
err := MarshallObject(rule, &writer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return fixResourceString(writer.String(), 14)
|
||||
}
|
||||
|
||||
func getOperatorDeploymentSpec() string {
|
||||
args := &cdioperator.FactoryArgs{
|
||||
Verbosity: *verbosity,
|
||||
DockerRepo: *dockerRepo,
|
||||
DockerTag: *dockertag,
|
||||
DeployClusterResources: *deployClusterResources,
|
||||
OperatorImage: *operatorImage,
|
||||
ControllerImage: *controllerImage,
|
||||
ImporterImage: *importerImage,
|
||||
ClonerImage: *clonerImage,
|
||||
APIServerImage: *apiServerImage,
|
||||
UploadProxyImage: *uploadProxyImage,
|
||||
UploadServerImage: *uploadServerImage,
|
||||
PullPolicy: *pullPolicy,
|
||||
Namespace: *namespace,
|
||||
}
|
||||
|
||||
spec := cdioperator.GetOperatorDeploymentSpec(args)
|
||||
|
||||
writer := strings.Builder{}
|
||||
|
||||
err := MarshallObject(spec, &writer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return fixResourceString(writer.String(), 14)
|
||||
}
|
||||
|
||||
func fixResourceString(in string, indention int) string {
|
||||
out := strings.Builder{}
|
||||
scanner := bufio.NewScanner(strings.NewReader(in))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
// remove separator lines
|
||||
if !strings.HasPrefix(line, "---") {
|
||||
// indent so that it fits into the manifest
|
||||
// spaces is is indention - 2, because we want to have 2 spaces less for being able to start an array
|
||||
spaces := strings.Repeat(" ", indention-2)
|
||||
if strings.HasPrefix(line, "apiGroups") {
|
||||
// spaces + array start
|
||||
out.WriteString(spaces + "- " + line + "\n")
|
||||
} else {
|
||||
// 2 more spaces
|
||||
out.WriteString(spaces + " " + line + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func generateFromFile(templFile string) {
|
||||
data := &templateData{
|
||||
Verbosity: *verbosity,
|
||||
DockerRepo: *dockerRepo,
|
||||
DockerTag: *dockertag,
|
||||
ControllerImage: *controllerImage,
|
||||
ImporterImage: *importerImage,
|
||||
ClonerImage: *clonerImage,
|
||||
APIServerImage: *apiServerImage,
|
||||
UploadProxyImage: *uploadProxyImage,
|
||||
UploadServerImage: *uploadServerImage,
|
||||
OperatorImage: *operatorImage,
|
||||
PullPolicy: *pullPolicy,
|
||||
Namespace: *namespace,
|
||||
Verbosity: *verbosity,
|
||||
DockerRepo: *dockerRepo,
|
||||
DockerTag: *dockertag,
|
||||
CsvVersion: *csvVersion,
|
||||
DeployClusterResources: *deployClusterResources,
|
||||
OperatorImage: *operatorImage,
|
||||
ControllerImage: *controllerImage,
|
||||
ImporterImage: *importerImage,
|
||||
ClonerImage: *clonerImage,
|
||||
APIServerImage: *apiServerImage,
|
||||
UploadProxyImage: *uploadProxyImage,
|
||||
UploadServerImage: *uploadServerImage,
|
||||
PullPolicy: *pullPolicy,
|
||||
Namespace: *namespace,
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(templFile, os.O_RDONLY, 0)
|
||||
@ -97,6 +190,40 @@ func generateFromFile(templFile string) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if strings.Contains(*csvVersion, initialCsvVersion) {
|
||||
data.ReplacesCsvVersion = ""
|
||||
} else {
|
||||
klog.Fatalf("Need to implement CSV upgrade to set ReplacesVersion in CSV when CSVVersion is greater than %s\n", initialCsvVersion)
|
||||
}
|
||||
|
||||
data.QuayRepository = *quayRepository
|
||||
data.QuayNamespace = *quayNamespace
|
||||
data.OperatorRules = getOperatorRules()
|
||||
data.OperatorDeploymentSpec = getOperatorDeploymentSpec()
|
||||
data.CDILogo = getCdiLogo(*cdiLogoPath)
|
||||
|
||||
// Read generated manifests in order to populate templated manifest
|
||||
genDir := *genManifestsPath
|
||||
|
||||
data.GeneratedManifests = make(map[string]string)
|
||||
|
||||
manifests, err := ioutil.ReadDir(genDir)
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to read directory %s: %v\n", templFile, err)
|
||||
}
|
||||
|
||||
for _, manifest := range manifests {
|
||||
if manifest.IsDir() {
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadFile(filepath.Join(genDir, manifest.Name()))
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to read file %s: %v\n", templFile, err)
|
||||
}
|
||||
|
||||
data.GeneratedManifests[manifest.Name()] = string(b)
|
||||
}
|
||||
|
||||
tmpl := template.Must(template.ParseFiles(templFile))
|
||||
err = tmpl.Execute(os.Stdout, data)
|
||||
if err != nil {
|
||||
@ -104,37 +231,117 @@ func generateFromFile(templFile string) {
|
||||
}
|
||||
}
|
||||
|
||||
func getCdiLogo(path string) string {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error retrieving cdi logo file: %v\n", err)
|
||||
}
|
||||
|
||||
// Read entire file into byte slice.
|
||||
reader := bufio.NewReader(file)
|
||||
content, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error reading cdi logo file: %v\n", err)
|
||||
}
|
||||
|
||||
// Encode as base64.
|
||||
encoded := base64.StdEncoding.EncodeToString(content)
|
||||
return encoded
|
||||
}
|
||||
|
||||
const (
|
||||
//ClusterResource - cluster resources
|
||||
ClusterResource string = "cluster"
|
||||
//OperatorResource - operator resources
|
||||
OperatorResource string = "operator"
|
||||
//NamespaceResource - namespace resources
|
||||
NamespaceResource string = "namespaces"
|
||||
)
|
||||
|
||||
type resourceGet func(string) ([]runtime.Object, error)
|
||||
type resourcetype func(string) bool
|
||||
type resourceTuple struct {
|
||||
resourcetype resourcetype
|
||||
resourceGet resourceGet
|
||||
}
|
||||
|
||||
var resourcesTable = map[string]resourceTuple{
|
||||
ClusterResource: {cdicluster.IsFactoryResource, getClusterResources},
|
||||
NamespaceResource: {namespaced.IsFactoryResource, getNamespacedResources},
|
||||
OperatorResource: {cdioperator.IsFactoryResource, getOperatorClusterResources},
|
||||
}
|
||||
|
||||
func generateFromCode(codeGroup string) {
|
||||
var resources []runtime.Object
|
||||
|
||||
crs, err := getClusterResources(codeGroup)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error getting cluster resources: %v\n", err)
|
||||
}
|
||||
|
||||
resources = append(resources, crs...)
|
||||
|
||||
nsrs, err := getNamespacedResources(codeGroup)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error getting namespaced resources: %v\n", err)
|
||||
}
|
||||
|
||||
resources = append(resources, nsrs...)
|
||||
for r, disptach := range resourcesTable {
|
||||
if disptach.resourcetype(codeGroup) {
|
||||
crs, err := disptach.resourceGet(codeGroup)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error getting %s resources: %v\n", r, err)
|
||||
}
|
||||
resources = append(resources, crs...)
|
||||
} //of codeGroup matches resource then get it
|
||||
} //iterate through all resources
|
||||
|
||||
for _, resource := range resources {
|
||||
err = MarshallObject(resource, os.Stdout)
|
||||
err := MarshallObject(resource, os.Stdout)
|
||||
if err != nil {
|
||||
klog.Fatalf("Error marshalling resource: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getClusterResources(codeGroup string) ([]runtime.Object, error) {
|
||||
args := &cdicluster.FactoryArgs{
|
||||
Namespace: *namespace,
|
||||
const (
|
||||
//ClusterResourcesCodeGroupEverything - generate all cluster resources
|
||||
ClusterResourcesCodeGroupEverything string = "cluster-everything"
|
||||
//NamespaceResourcesCodeGroupEverything - generate all namespace resources
|
||||
NamespaceResourcesCodeGroupEverything string = "namespace-everything"
|
||||
//ClusterResourcesCodeOperatorGroupEverything - generate all operator resources
|
||||
ClusterResourcesCodeOperatorGroupEverything string = "operator-everything"
|
||||
)
|
||||
|
||||
func getOperatorClusterResources(codeGroup string) ([]runtime.Object, error) {
|
||||
args := &cdioperator.FactoryArgs{
|
||||
Verbosity: *verbosity,
|
||||
DockerRepo: *dockerRepo,
|
||||
DockerTag: *dockertag,
|
||||
DeployClusterResources: *deployClusterResources,
|
||||
OperatorImage: *operatorImage,
|
||||
ControllerImage: *controllerImage,
|
||||
ImporterImage: *importerImage,
|
||||
ClonerImage: *clonerImage,
|
||||
APIServerImage: *apiServerImage,
|
||||
UploadProxyImage: *uploadProxyImage,
|
||||
UploadServerImage: *uploadServerImage,
|
||||
PullPolicy: *pullPolicy,
|
||||
Namespace: *namespace,
|
||||
}
|
||||
|
||||
if codeGroup == "everything" {
|
||||
if codeGroup == ClusterResourcesCodeOperatorGroupEverything {
|
||||
return cdioperator.CreateAllOperatorResources(args)
|
||||
}
|
||||
|
||||
return cdioperator.CreateOperatorResourceGroup(codeGroup, args)
|
||||
}
|
||||
|
||||
func getClusterResources(codeGroup string) ([]runtime.Object, error) {
|
||||
args := &cdicluster.FactoryArgs{
|
||||
Verbosity: *verbosity,
|
||||
DockerRepo: *dockerRepo,
|
||||
DockerTag: *dockertag,
|
||||
DeployClusterResources: *deployClusterResources,
|
||||
ControllerImage: *controllerImage,
|
||||
ImporterImage: *importerImage,
|
||||
ClonerImage: *clonerImage,
|
||||
APIServerImage: *apiServerImage,
|
||||
UploadProxyImage: *uploadProxyImage,
|
||||
UploadServerImage: *uploadServerImage,
|
||||
PullPolicy: *pullPolicy,
|
||||
Namespace: *namespace,
|
||||
}
|
||||
|
||||
if codeGroup == ClusterResourcesCodeGroupEverything {
|
||||
return cdicluster.CreateAllResources(args)
|
||||
}
|
||||
|
||||
@ -156,7 +363,7 @@ func getNamespacedResources(codeGroup string) ([]runtime.Object, error) {
|
||||
Namespace: *namespace,
|
||||
}
|
||||
|
||||
if codeGroup == "everything" {
|
||||
if codeGroup == NamespaceResourcesCodeGroupEverything {
|
||||
return cdinamespaced.CreateAllResources(args)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user