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:
annastopel 2019-04-01 14:29:17 +03:00
parent 9ed8832aa2
commit f634cdaa17
38 changed files with 2080 additions and 487 deletions

View File

@ -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

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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
View 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
```

View File

@ -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

View File

@ -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;}' \;

View File

@ -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"

View File

@ -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
View 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
View 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;}' \;
}

View 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"}}

View File

@ -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

View File

@ -90,4 +90,3 @@ spec:
- name: sec-docker-reg
port: 443
targetPort: 443

View File

@ -2,3 +2,6 @@ apiVersion: cdi.kubevirt.io/v1alpha1
kind: CDI
metadata:
name: cdi
namespace: {{.Namespace}}
spec:
imagePullPolicy: {{.PullPolicy}}

View 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"}}

View File

@ -0,0 +1 @@
{{index .GeneratedManifests "cdi-crd.yaml"}}

View File

@ -0,0 +1,4 @@
packageName: {{.QuayRepository}}
channels:
- name: beta
currentCSV: cdioperator.{{.CsvVersion}}

View File

@ -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'

View File

@ -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"}}

View 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"

View 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

View File

@ -0,0 +1,5 @@
apiVersion: operators.coreos.com/v1alpha2
kind: OperatorGroup
metadata:
name: {{.Namespace}}
namespace: {{.Namespace}}

View File

@ -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{

View File

@ -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)
}

View File

@ -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
}

View File

@ -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

View File

@ -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",

View File

@ -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{

View File

@ -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,
},
}
}

View File

@ -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),
},
}
}

View File

@ -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 {

View File

@ -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",

View 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()
}

View 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
}

View 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,
},
}
}

View 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,
},
}
}

View File

@ -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)
}