Che operator should be able to install DevWorkspace operator (#689)

* Che operator should be able to install DevWorkspace operator

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fix typo

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Add missing roles

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update cluster roles

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update nightly bundle

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fixes

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Add missing files

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fixes

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fix tests

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Add tests

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update nightly bundle

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Improvements

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Add logs

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fix test

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Fix tests

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update nightly bundle

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update clusterroles

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update test

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update test

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

* Update nightly bundle

Signed-off-by: Anatolii Bazko <abazko@redhat.com>
pull/705/head^2
Anatolii Bazko 2021-03-04 21:59:34 +02:00 committed by GitHub
parent 80e33df8cb
commit 052a637430
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 16511 additions and 467 deletions

View File

@ -39,6 +39,14 @@ runTests() {
provisionOAuth
startNewWorkspace
waitWorkspaceStart
# Dev Workspace controller tests
deployDevWorkspaceController
waitDevWorkspaceControllerStarted
sleep 10s
createWorksaceDevWorkspaceController
waitWorkspaceStartedDevWorkspaceController
}
initDefaults

49
.github/bin/common.sh vendored
View File

@ -28,6 +28,7 @@ catchFinish() {
initDefaults() {
export RAM_MEMORY=8192
export NAMESPACE="eclipse-che"
export USER_NAMEPSACE="che-che"
export ARTIFACTS_DIR="/tmp/artifacts-che"
export TEMPLATES=${OPERATOR_REPO}/tmp
export OPERATOR_IMAGE="test/che-operator:test"
@ -338,3 +339,51 @@ login() {
chectl auth:login --chenamespace=${NAMESPACE}
fi
}
deployDevWorkspaceController() {
oc patch checluster eclipse-che -n ${NAMESPACE} --type=merge -p '{"spec":{"devWorkspace": {"enable": true}}}'
}
waitDevWorkspaceControllerStarted() {
n=0
while [ $n -le 24 ]
do
webhooks=$(oc get mutatingWebhookConfiguration --all-namespaces)
if [[ $webhooks =~ .*controller.devfile.io.* ]]; then
echo "[INFO] Dev Workspace controller has been deployed"
return
fi
sleep 5
n=$(( n+1 ))
done
echo "[ERROR] Failed to deploy Dev Workspace controller"
OPERATOR_POD=$(oc get pods -o json -n ${NAMESPACE} | jq -r '.items[] | select(.metadata.name | test("che-operator-")).metadata.name')
oc logs ${OPERATOR_POD} -n ${NAMESPACE}
exit 1
}
createWorksaceDevWorkspaceController () {
oc apply -f https://raw.githubusercontent.com/devfile/devworkspace-operator/main/samples/flattened_theia-next.yaml -n ${NAMESPACE}
}
waitWorkspaceStartedDevWorkspaceController() {
n=0
while [ $n -le 24 ]
do
pods=$(oc get pods -n ${NAMESPACE})
if [[ $pods =~ .*Running.* ]]; then
echo "[INFO] Wokrspace started succesfully"
return
fi
sleep 5
n=$(( n+1 ))
done
echo "Failed to start a workspace"
exit 1
}

View File

@ -13,6 +13,8 @@
# NOTE: using registry.redhat.io/rhel8/go-toolset requires login, which complicates automation
# NOTE: since updateBaseImages.sh does not support other registries than RHCC, update to RHEL8
# https://access.redhat.com/containers/?tab=tags#/registry.access.redhat.com/devtools/go-toolset-rhel7
ARG DEV_WORKSPACE_CONTROLLER_VERSION="master"
FROM registry.access.redhat.com/devtools/go-toolset-rhel7:1.13.15-4 as builder
ENV PATH=/opt/rh/go-toolset-1.13/root/usr/bin:${PATH} \
GOPATH=/go/
@ -21,11 +23,17 @@ USER root
ADD . /che-operator
WORKDIR /che-operator
# build operator
RUN export ARCH="$(uname -m)" && if [[ ${ARCH} == "x86_64" ]]; then export ARCH="amd64"; elif [[ ${ARCH} == "aarch64" ]]; then export ARCH="arm64"; fi && \
export MOCK_API=true && \
go test -mod=vendor -v ./... && \
GOOS=linux GOARCH=${ARCH} CGO_ENABLED=0 go build -mod=vendor -o /tmp/che-operator/che-operator cmd/manager/main.go
# download devworkspace-operator templates
RUN curl -L https://api.github.com/repos/devfile/devworkspace-operator/zipball/${DEV_WORKSPACE_CONTROLLER_VERSION} > /tmp/devworkspace-operator.zip && \
unzip /tmp/devworkspace-operator.zip */deploy/deployment/* -d /tmp
# https://access.redhat.com/containers/?tab=tags#/registry.access.redhat.com/ubi8-minimal
FROM registry.access.redhat.com/ubi8-minimal:8.3-291
@ -34,6 +42,8 @@ COPY --from=builder /che-operator/templates/keycloak-provision.sh /tmp/keycloak-
COPY --from=builder /che-operator/templates/oauth-provision.sh /tmp/oauth-provision.sh
COPY --from=builder /che-operator/templates/delete-identity-provider.sh /tmp/delete-identity-provider.sh
COPY --from=builder /che-operator/templates/create-github-identity-provider.sh /tmp/create-github-identity-provider.sh
COPY --from=builder /tmp/devfile-devworkspace-operator-*/deploy /tmp/devworkspace-operator/templates
# apply CVE fixes, if required
RUN microdnf update -y librepo libnghttp2 && microdnf install httpd-tools && microdnf clean all && rm -rf /var/cache/yum && echo "Installed Packages" && rpm -qa | sort -V && echo "End Of Installed Packages"
CMD ["che-operator"]

View File

@ -25,6 +25,7 @@ rules:
- create
- get
- delete
- deletecollection
- list
- patch
- update
@ -118,6 +119,9 @@ rules:
- get
- create
- delete
- list
- update
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
@ -127,6 +131,8 @@ rules:
- create
- update
- delete
- list
- watch
- apiGroups:
- org.eclipse.che
resources:
@ -156,13 +162,24 @@ rules:
verbs:
- get
- apiGroups:
- ''
- ""
resources:
- configmaps
- persistentvolumeclaims
- pods
- secrets
- serviceaccounts
- services
verbs:
- '*'
- apiGroups:
- ""
resources:
- configmaps/status
verbs:
- get
- create
- watch
- update
- patch
- apiGroups:
- ''
resources:
@ -175,92 +192,121 @@ rules:
- secrets
verbs:
- list
- apiGroups:
- ''
resources:
- secrets
verbs:
- list
- get
- create
- delete
- apiGroups:
- ''
resources:
- persistentvolumeclaims
verbs:
- create
- get
- list
- watch
- apiGroups:
- ''
resources:
- pods
verbs:
- get
- list
- create
- watch
- delete
- apiGroups:
- apps
- extensions
resources:
- deployments
- replicasets
verbs:
- get
- list
- create
- patch
- watch
- delete
- apiGroups:
- ''
resources:
- services
verbs:
- list
- create
- delete
- apiGroups:
- ''
resources:
- configmaps
verbs:
- get
- create
- delete
- list
- '*'
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- list
- '*'
- apiGroups:
- route.openshift.io
resources:
- routes/custom-host
verbs:
- create
- delete
- apiGroups:
- ''
resources:
- events
verbs:
- watch
- create
- patch
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
verbs:
- create
- get
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resourceNames:
- devworkspace-controller
resources:
- replicasets
- deployments/finalizers
verbs:
- list
- get
- patch
- delete
- update
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- list
- '*'
- apiGroups:
- workspace.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- controller.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- create
- watch
- get
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- operators.coreos.com
resources:
- subscriptions
verbs:
- get
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- create
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch

View File

@ -163,3 +163,8 @@ spec:
metrics:
# Enables `metrics` the Che server endpoint.
enable: true
devWorkspace:
# Deploys the DevWorkspace Operator in the cluster.
# Does nothing when a matching version of the Operator is already installed.
# Fails when a non-matching version of the Operator is already installed.
enable: false

View File

@ -305,6 +305,15 @@ spec:
`latest` images, and `IfNotPresent` in other cases.
type: string
type: object
devWorkspace:
description: Dev Workspace operator configuration
properties:
enable:
description: Deploys the DevWorkspace Operator in the cluster. Does
nothing when a matching version of the Operator is already installed.
Fails when a non-matching version of the Operator is already installed.
type: boolean
type: object
imagePuller:
description: Kubernetes Image Puller configuration
properties:

View File

@ -30,6 +30,9 @@ metadata:
"chePostgresUser": "",
"externalDb": false
},
"devWorkspace": {
"enable": false
},
"k8s": {
"ingressClass": "",
"ingressDomain": "",
@ -73,13 +76,13 @@ metadata:
categories: Developer Tools
certified: "false"
containerImage: quay.io/eclipse/che-operator:nightly
createdAt: "2021-03-04T13:35:29Z"
createdAt: "2021-03-04T16:28:02Z"
description: A Kube-native development solution that delivers portable and collaborative
developer workspaces.
operatorframework.io/suggested-namespace: eclipse-che
repository: https://github.com/eclipse/che-operator
support: Eclipse Foundation
name: eclipse-che-preview-kubernetes.v7.28.0-108.nightly
name: eclipse-che-preview-kubernetes.v7.28.0-120.nightly
namespace: placeholder
spec:
apiservicedefinitions: {}
@ -292,6 +295,9 @@ spec:
- get
- create
- delete
- list
- update
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
@ -301,6 +307,8 @@ spec:
- create
- update
- delete
- list
- watch
- apiGroups:
- org.eclipse.che
resources:
@ -319,11 +327,22 @@ spec:
- apiGroups:
- ""
resources:
- configmaps
- persistentvolumeclaims
- pods
- secrets
- serviceaccounts
- services
verbs:
- '*'
- apiGroups:
- ""
resources:
- configmaps/status
verbs:
- get
- create
- watch
- update
- patch
- apiGroups:
- ""
resources:
@ -336,87 +355,112 @@ spec:
- secrets
verbs:
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- list
- get
- create
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- create
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- create
- watch
- delete
- apiGroups:
- apps
- extensions
resources:
- deployments
- replicasets
verbs:
- get
- list
- create
- patch
- watch
- delete
- apiGroups:
- ""
resources:
- services
verbs:
- list
- create
- delete
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- create
- delete
- list
- '*'
- apiGroups:
- ""
resources:
- events
verbs:
- watch
- create
- patch
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
verbs:
- create
- get
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resourceNames:
- devworkspace-controller
resources:
- replicasets
- deployments/finalizers
verbs:
- list
- get
- patch
- delete
- update
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- list
- '*'
- apiGroups:
- workspace.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- controller.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- create
- watch
- get
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- operators.coreos.com
resources:
- subscriptions
verbs:
- get
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- create
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch
serviceAccountName: che-operator
- rules:
- apiGroups:
@ -675,4 +719,4 @@ spec:
maturity: stable
provider:
name: Eclipse Foundation
version: 7.28.0-108.nightly
version: 7.28.0-120.nightly

View File

@ -305,6 +305,15 @@ spec:
`latest` images, and `IfNotPresent` in other cases.
type: string
type: object
devWorkspace:
description: Dev Workspace operator configuration
properties:
enable:
description: Deploys the DevWorkspace Operator in the cluster. Does
nothing when a matching version of the Operator is already installed.
Fails when a non-matching version of the Operator is already installed.
type: boolean
type: object
imagePuller:
description: Kubernetes Image Puller configuration
properties:

View File

@ -30,6 +30,9 @@ metadata:
"chePostgresUser": "",
"externalDb": false
},
"devWorkspace": {
"enable": false
},
"metrics": {
"enable": true
},
@ -64,13 +67,13 @@ metadata:
categories: Developer Tools, OpenShift Optional
certified: "false"
containerImage: quay.io/eclipse/che-operator:nightly
createdAt: "2021-03-04T13:35:37Z"
createdAt: "2021-03-04T16:28:11Z"
description: A Kube-native development solution that delivers portable and collaborative
developer workspaces in OpenShift.
operatorframework.io/suggested-namespace: eclipse-che
repository: https://github.com/eclipse/che-operator
support: Eclipse Foundation
name: eclipse-che-preview-openshift.v7.28.0-108.nightly
name: eclipse-che-preview-openshift.v7.28.0-120.nightly
namespace: placeholder
spec:
apiservicedefinitions: {}
@ -246,6 +249,7 @@ spec:
- create
- get
- delete
- deletecollection
- list
- patch
- update
@ -339,6 +343,9 @@ spec:
- get
- create
- delete
- list
- update
- watch
- apiGroups:
- rbac.authorization.k8s.io
resources:
@ -348,6 +355,8 @@ spec:
- create
- update
- delete
- list
- watch
- apiGroups:
- org.eclipse.che
resources:
@ -379,11 +388,22 @@ spec:
- apiGroups:
- ""
resources:
- configmaps
- persistentvolumeclaims
- pods
- secrets
- serviceaccounts
- services
verbs:
- '*'
- apiGroups:
- ""
resources:
- configmaps/status
verbs:
- get
- create
- watch
- update
- patch
- apiGroups:
- ""
resources:
@ -396,95 +416,124 @@ spec:
- secrets
verbs:
- list
- apiGroups:
- ""
resources:
- secrets
verbs:
- list
- get
- create
- delete
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- create
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- create
- watch
- delete
- apiGroups:
- apps
- extensions
resources:
- deployments
- replicasets
verbs:
- get
- list
- create
- patch
- watch
- delete
- apiGroups:
- ""
resources:
- services
verbs:
- list
- create
- delete
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- create
- delete
- list
- '*'
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- list
- '*'
- apiGroups:
- route.openshift.io
resources:
- routes/custom-host
verbs:
- create
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- watch
- create
- patch
- apiGroups:
- monitoring.coreos.com
resources:
- servicemonitors
verbs:
- create
- get
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resourceNames:
- devworkspace-controller
resources:
- replicasets
- deployments/finalizers
verbs:
- list
- get
- patch
- delete
- update
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- list
- '*'
- apiGroups:
- workspace.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- controller.devfile.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
- validatingwebhookconfigurations
verbs:
- create
- watch
- get
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- operators.coreos.com
resources:
- subscriptions
verbs:
- get
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- create
- apiGroups:
- ""
resources:
- namespaces
verbs:
- list
- watch
serviceAccountName: che-operator
- rules:
- apiGroups:
@ -747,4 +796,4 @@ spec:
maturity: stable
provider:
name: Eclipse Foundation
version: 7.28.0-108.nightly
version: 7.28.0-120.nightly

View File

@ -306,6 +306,15 @@ spec:
`latest` images, and `IfNotPresent` in other cases.
type: string
type: object
devWorkspace:
description: Dev Workspace operator configuration
properties:
enable:
description: Deploys the DevWorkspace Operator in the cluster. Does
nothing when a matching version of the Operator is already installed.
Fails when a non-matching version of the Operator is already installed.
type: boolean
type: object
imagePuller:
description: Kubernetes Image Puller configuration
properties:

1
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/sirupsen/logrus v1.4.2
golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914
k8s.io/api v0.18.2
k8s.io/apiextensions-apiserver v0.18.2
k8s.io/apimachinery v0.18.2
k8s.io/client-go v12.0.0+incompatible
sigs.k8s.io/controller-runtime v0.6.0

1
go.sum
View File

@ -1127,6 +1127,7 @@ k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+
k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ=
k8s.io/kubelet v0.0.0-20191016114556-7841ed97f1b2/go.mod h1:SBvrtLbuePbJygVXGGCMtWKH07+qrN2dE1iMnteSG8E=
k8s.io/kubernetes v1.16.0/go.mod h1:nlP2zevWKRGKuaaVbKIwozU0Rjg9leVDXkL4YTtjmVs=
k8s.io/kubernetes v1.16.2 h1:k0f/OVp6Yfv+UMTm6VYKhqjRgcvHh4QhN9coanjrito=
k8s.io/kubernetes v1.16.2/go.mod h1:SmhGgKfQ30imqjFVj8AI+iW+zSyFsswNErKYeTfgoH0=
k8s.io/legacy-cloud-providers v0.0.0-20191016115753-cf0698c3a16b/go.mod h1:tKW3pKqdRW8pMveUTpF5pJuCjQxg6a25iLo+Z9BXVH0=
k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs=

View File

@ -12,22 +12,13 @@
set -e
command -v delv >/dev/null 2>&1 || { echo "operator-sdk is not installed. Aborting."; exit 1; }
command -v operator-sdk >/dev/null 2>&1 || { echo -e $RED"operator-sdk is not installed. Aborting."$NC; exit 1; }
command -v delv >/dev/null 2>&1 || { echo "delv is not installed. Aborting."; exit 1; }
command -v operator-sdk >/dev/null 2>&1 || { echo "operator-sdk is not installed. Aborting."; exit 1; }
usage () {
echo "Usage: $0 [-w WORKDIR] [-s SOURCE_PATH] -r [CSV_FILE_PATH_REGEXP] -t [IMAGE_TAG] "
echo "Example: $0 -w $(pwd) -r \"eclipse-che-preview-.*/eclipse-che-preview-.*\.v7.15.0.*yaml\" -t 7.15.0"
}
while [[ "$#" -gt 0 ]]; do
case $1 in
'-n') CHE_NAMESPACE="$2"; shift 1;;
'-cr') CR="$2"; shift 1;;
'--help'|'-h') usage; exit;;
esac
shift 1
done
ECLIPSE_CHE_NAMESPACE="eclipse-che"
ECLIPSE_CHE_CR="./deploy/crds/org_v1_che_cr.yaml"
ECLIPSE_CHE_CRD="./deploy/crds/org_v1_che_crd.yaml"
DEV_WORKSPACE_CONTROLLER_VERSION="master"
# Stop execution on any error
trap "catchFinish" EXIT SIGINT
@ -41,40 +32,70 @@ catchFinish() {
fi
}
if [ -z "${CHE_NAMESPACE}" ];then
CHE_NAMESPACE=che
fi
echo "[INFO] Namespace: ${CHE_NAMESPACE}"
usage () {
echo "Usage: $0 [-n ECLIPSE_CHE_NAMESPACE] [-cr ECLIPSE_CHE_CR] "
}
set +e
kubectl create namespace $CHE_NAMESPACE
set -e
while [[ "$#" -gt 0 ]]; do
case $1 in
'-n') ECLIPSE_CHE_NAMESPACE="$2"; shift 1;;
'-cr') ECLIPSE_CHE_CR="$2"; shift 1;;
'--help'|'-h') usage; exit;;
esac
shift 1
done
if [ -z "${CR}" ]; then
CR="./deploy/crds/org_v1_che_cr.yaml"
fi
echo "[INFO] CR file path: ${CR}"
prepareTemplates() {
cp templates/keycloak-provision.sh /tmp/keycloak-provision.sh
cp templates/delete-identity-provider.sh /tmp/delete-identity-provider.sh
cp templates/create-github-identity-provider.sh /tmp/create-github-identity-provider.sh
cp templates/oauth-provision.sh /tmp/oauth-provision.sh
kubectl apply -f deploy/crds/org_v1_che_crd.yaml
kubectl apply -f "${CR}" -n $CHE_NAMESPACE
cp templates/keycloak-provision.sh /tmp/keycloak-provision.sh
cp templates/delete-identity-provider.sh /tmp/delete-identity-provider.sh
cp templates/create-github-identity-provider.sh /tmp/create-github-identity-provider.sh
cp templates/oauth-provision.sh /tmp/oauth-provision.sh
# Download Dev Workspace operator templates
echo "[INFO] Downloading Dev Workspace operator templates ..."
rm /tmp/devworkspace-operator.zip
rm -rf /tmp/devfile-devworkspace-operator-*
rm -rf /tmp/devworkspace-operator/
mkdir -p /tmp/devworkspace-operator/templates
ENV_FILE=/tmp/che-operator-debug.env
rm -rf "${ENV_FILE}"
touch "${ENV_FILE}"
CLUSTER_API_URL=$(oc whoami --show-server=true) || true
if [ -n "${CLUSTER_API_URL}" ]; then
echo "CLUSTER_API_URL='${CLUSTER_API_URL}'" >> "${ENV_FILE}"
echo "[INFO] Set up cluster api url: ${CLUSTER_API_URL}"
fi
echo "WATCH_NAMESPACE='${CHE_NAMESPACE}'" >> ${ENV_FILE}
curl -sL https://api.github.com/repos/devfile/devworkspace-operator/zipball/${DEV_WORKSPACE_CONTROLLER_VERSION} > /tmp/devworkspace-operator.zip
echo "[WARN] Make sure that your CR contains valid ingress domain!"
unzip /tmp/devworkspace-operator.zip */deploy/deployment/* -d /tmp
cp -r /tmp/devfile-devworkspace-operator*/deploy/* /tmp/devworkspace-operator/templates
echo "[INFO] Downloading Dev Workspace operator templates completed."
}
operator-sdk run --local --watch-namespace ${CHE_NAMESPACE} --enable-delve &
OPERATOR_SDK_PID=$!
createNamespace() {
set +e
kubectl create namespace $ECLIPSE_CHE_NAMESPACE
set -e
}
wait ${OPERATOR_SDK_PID}
applyCRandCRD() {
kubectl apply -f ${ECLIPSE_CHE_CRD}
kubectl apply -f ${ECLIPSE_CHE_CR} -n $ECLIPSE_CHE_NAMESPACE
}
runDebug() {
ENV_FILE=/tmp/che-operator-debug.env
rm -rf "${ENV_FILE}"
touch "${ENV_FILE}"
CLUSTER_API_URL=$(oc whoami --show-server=true) || true
if [ -n "${CLUSTER_API_URL}" ]; then
echo "CLUSTER_API_URL='${CLUSTER_API_URL}'" >> "${ENV_FILE}"
echo "[INFO] Set up cluster api url: ${CLUSTER_API_URL}"
fi
echo "WATCH_NAMESPACE='${ECLIPSE_CHE_NAMESPACE}'" >> ${ENV_FILE}
echo "[WARN] Make sure that your CR contains valid ingress domain!"
operator-sdk run --local --watch-namespace ${ECLIPSE_CHE_NAMESPACE} --enable-delve &
OPERATOR_SDK_PID=$!
wait ${OPERATOR_SDK_PID}
}
prepareTemplates
createNamespace
applyCRandCRD
runDebug

View File

@ -27,6 +27,7 @@ init() {
RELEASE_DIR=$(cd "$(dirname "$0")"; pwd)
FORCE_UPDATE=""
BUILDX_PLATFORMS="linux/amd64,linux/ppc64le"
DEV_WORKSPACE_CONTROLLER_VERSION="master"
if [[ $# -lt 1 ]]; then usage; exit; fi
@ -39,6 +40,7 @@ init() {
'--release-olm-files') RELEASE_OLM_FILES=true; shift 0;;
'--update-nightly-olm-files') UPDATE_NIGHTLY_OLM_FILES=true; shift 0;;
'--prepare-community-operators-update') PREPARE_COMMUNITY_OPERATORS_UPDATE=true; shift 0;;
'--dev-workspace-controller-version') DEV_WORKSPACE_CONTROLLER_VERSION=$2; shift 1;;
'--force') FORCE_UPDATE="--force"; shift 0;;
'--help'|'-h') usage; exit;;
esac
@ -161,7 +163,7 @@ releaseOperatorCode() {
docker login quay.io -u "${QUAY_ECLIPSE_CHE_USERNAME}" -p "${QUAY_ECLIPSE_CHE_PASSWORD}"
echo "[INFO] releaseOperatorCode :: Build operator image in platforms: $BUILDX_PLATFORMS"
docker buildx build --platform "$BUILDX_PLATFORMS" --push -t "quay.io/eclipse/che-operator:${RELEASE}" .
docker buildx build --build-arg DEV_WORKSPACE_CONTROLLER_VERSION=${DEV_WORKSPACE_CONTROLLER_VERSION} --platform "$BUILDX_PLATFORMS" --push -t "quay.io/eclipse/che-operator:${RELEASE}" .
}
updateNightlyOlmFiles() {

View File

@ -54,6 +54,9 @@ type CheClusterSpec struct {
// Kubernetes Image Puller configuration
// +optional
ImagePuller CheClusterSpecImagePuller `json:"imagePuller"`
// Dev Workspace operator configuration
// +optional
DevWorkspace CheClusterSpecDevWorkspace `json:"devWorkspace"`
}
// +k8s:openapi-gen=true
@ -543,6 +546,19 @@ type CheClusterSpecImagePuller struct {
Spec chev1alpha1.KubernetesImagePullerSpec `json:"spec"`
}
// +k8s:openapi-gen=true
// Settings for installation and configuration of the Dev Workspace operator
// See https://github.com/devfile/devworkspace-operator
type CheClusterSpecDevWorkspace struct {
// Deploys the DevWorkspace Operator in the cluster.
// Does nothing when a matching version of the Operator is already installed.
// Fails when a non-matching version of the Operator is already installed.
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=false
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Enable Dev Workspace operator"
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.x-descriptors="urn:alm:descriptor:com.tectonic.ui:booleanSwitch"
Enable bool `json:"enable"`
}
// CheClusterStatus defines the observed state of Che installation
type CheClusterStatus struct {
// OpenShift OAuth secret that contains user credentials for HTPasswd identity provider.

View File

@ -80,6 +80,7 @@ func (in *CheClusterSpec) DeepCopyInto(out *CheClusterSpec) {
out.Metrics = in.Metrics
out.K8s = in.K8s
out.ImagePuller = in.ImagePuller
out.DevWorkspace = in.DevWorkspace
return
}
@ -139,6 +140,22 @@ func (in *CheClusterSpecDB) DeepCopy() *CheClusterSpecDB {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterSpecDevWorkspace) DeepCopyInto(out *CheClusterSpecDevWorkspace) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CheClusterSpecDevWorkspace.
func (in *CheClusterSpecDevWorkspace) DeepCopy() *CheClusterSpecDevWorkspace {
if in == nil {
return nil
}
out := new(CheClusterSpecDevWorkspace)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CheClusterSpecImagePuller) DeepCopyInto(out *CheClusterSpecImagePuller) {
*out = *in

View File

@ -20,6 +20,7 @@ import (
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/deploy"
devworkspace "github.com/eclipse/che-operator/pkg/deploy/dev-workspace"
devfile_registry "github.com/eclipse/che-operator/pkg/deploy/devfile-registry"
"github.com/eclipse/che-operator/pkg/deploy/gateway"
identity_provider "github.com/eclipse/che-operator/pkg/deploy/identity-provider"
@ -34,10 +35,12 @@ import (
routev1 "github.com/openshift/api/route/v1"
userv1 "github.com/openshift/api/user/v1"
"github.com/sirupsen/logrus"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
rbac "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -140,6 +143,16 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
}
}
// register Extension in the scheme
if err := apiextensionsv1.AddToScheme(mgr.GetScheme()); err != nil {
logrus.Errorf("Failed to add Extension to scheme: %s", err)
}
// register Admission in the scheme
if err := admissionregistrationv1.AddToScheme(mgr.GetScheme()); err != nil {
logrus.Errorf("Failed to add Admission to scheme: %s", err)
}
// register RBAC in the scheme
if err := rbac.AddToScheme(mgr.GetScheme()); err != nil {
logrus.Errorf("Failed to add RBAC to scheme: %s", err)
@ -425,6 +438,16 @@ func (r *ReconcileChe) Reconcile(request reconcile.Request) (reconcile.Result, e
}
}
// Reconcile Dev Workspace Operator
done, err := devworkspace.ReconcileDevWorkspace(deployContext)
if !done {
if err != nil {
logrus.Error(err)
}
// We should `Requeue` since we don't watch Dev Workspace controller objects
return reconcile.Result{RequeueAfter: time.Second}, err
}
// Read proxy configuration
proxy, err := r.getProxyConfiguration(instance)
if err != nil {

View File

@ -833,8 +833,9 @@ func TestCheController(t *testing.T) {
}
clusterAPI := deploy.ClusterAPI{
Client: r.client,
Scheme: r.scheme,
Client: r.client,
NonCachedClient: r.client,
Scheme: r.scheme,
}
deployContext := &deploy.DeployContext{

View File

@ -18,8 +18,6 @@ import (
"os"
"strings"
"sigs.k8s.io/yaml"
"github.com/eclipse/che-operator/pkg/util"
"github.com/sirupsen/logrus"
appsv1 "k8s.io/api/apps/v1"
@ -424,12 +422,7 @@ func InitDefaultsFromEnv() {
func InitTestDefaultsFromDeployment(deploymentFile string) error {
operator := &appsv1.Deployment{}
data, err := ioutil.ReadFile(deploymentFile)
if err != nil {
return err
}
err = yaml.Unmarshal(data, operator)
err := util.ReadObject(deploymentFile, operator)
if err != nil {
return err
}

View File

@ -0,0 +1,223 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devworkspace
import (
"context"
"errors"
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/util"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)
const (
DevWorkspaceNamespace = "devworkspace-controller"
DevWorkspaceWebhookName = "controller.devfile.io"
DevWorkspaceServiceAccount = "devworkspace-controller-serviceaccount"
DevWorkspaceDeploymentName = "devworkspace-controller-manager"
DevWorkspaceTemplates = "/tmp/devworkspace-operator/templates/deployment/openshift/objects"
DevWorkspaceServiceAccountFile = DevWorkspaceTemplates + "/devworkspace-controller-serviceaccount.ServiceAccount.yaml"
DevWorkspaceRoleFile = DevWorkspaceTemplates + "/devworkspace-controller-leader-election-role.Role.yaml"
DevWorkspaceClusterRoleFile = DevWorkspaceTemplates + "/devworkspace-controller-role.ClusterRole.yaml"
DevWorkspaceProxyClusterRoleFile = DevWorkspaceTemplates + "/devworkspace-controller-proxy-role.ClusterRole.yaml"
DevWorkspaceViewWorkspacesClusterRoleFile = DevWorkspaceTemplates + "/devworkspace-controller-view-workspaces.ClusterRole.yaml"
DevWorkspaceEditWorkspacesClusterRoleFile = DevWorkspaceTemplates + "/devworkspace-controller-edit-workspaces.ClusterRole.yaml"
DevWorkspaceRoleBindingFile = DevWorkspaceTemplates + "/devworkspace-controller-leader-election-rolebinding.RoleBinding.yaml"
DevWorkspaceClusterRoleBindingFile = DevWorkspaceTemplates + "/devworkspace-controller-rolebinding.ClusterRoleBinding.yaml"
DevWorkspaceProxyClusterRoleBindingFile = DevWorkspaceTemplates + "/devworkspace-controller-proxy-rolebinding.ClusterRoleBinding.yaml"
DevWorkspaceWorkspaceRoutingCRDFile = DevWorkspaceTemplates + "/workspaceroutings.controller.devfile.io.CustomResourceDefinition.yaml"
DevWorkspaceTemplatesCRDFile = DevWorkspaceTemplates + "/devworkspacetemplates.workspace.devfile.io.CustomResourceDefinition.yaml"
DevWorkspaceComponentsCRDFile = DevWorkspaceTemplates + "/components.controller.devfile.io.CustomResourceDefinition.yaml"
DevWorkspaceCRDFile = DevWorkspaceTemplates + "/devworkspaces.workspace.devfile.io.CustomResourceDefinition.yaml"
DevWorkspaceConfigMapFile = DevWorkspaceTemplates + "/devworkspace-controller-configmap.ConfigMap.yaml"
DevWorkspaceDeploymentFile = DevWorkspaceTemplates + "/devworkspace-controller-manager.Deployment.yaml"
WebTerminalOperatorSubscriptionName = "web-terminal"
WebTerminalOperatorNamespace = "openshift-operators"
)
var (
// cachedObjects
cachedObj = make(map[string]metav1.Object)
syncItems = []func(*deploy.DeployContext) (bool, error){
createNamespace,
syncServiceAccount,
syncClusterRole,
syncProxyClusterRole,
syncEditWorkspacesClusterRole,
syncViewWorkspacesClusterRole,
syncRole,
syncRoleBinding,
syncClusterRoleBinding,
syncProxyClusterRoleBinding,
syncCRD,
syncComponentsCRD,
syncTemplatesCRD,
syncWorkspaceRoutingCRD,
syncConfigMap,
syncDeployment,
}
)
func ReconcileDevWorkspace(deployContext *deploy.DeployContext) (bool, error) {
if !util.IsOpenShift4 || !util.IsOAuthEnabled(deployContext.CheCluster) {
return true, nil
}
if !deployContext.CheCluster.Spec.DevWorkspace.Enable {
return true, nil
}
devWorkspaceWebhookExists, err := deploy.IsExists(
deployContext,
client.ObjectKey{Name: DevWorkspaceWebhookName},
&admissionregistrationv1.MutatingWebhookConfiguration{},
)
if err != nil {
return false, err
}
if !devWorkspaceWebhookExists {
for _, syncItem := range syncItems {
done, err := syncItem(deployContext)
if !util.IsTestMode() {
if !done {
return false, err
}
}
}
} else {
if err := checkWebTerminalSubscription(deployContext); err != nil {
return false, err
}
}
return true, nil
}
func checkWebTerminalSubscription(deployContext *deploy.DeployContext) error {
subscription := &operatorsv1alpha1.Subscription{}
if err := deployContext.ClusterAPI.NonCachedClient.Get(
context.TODO(),
types.NamespacedName{
Name: WebTerminalOperatorSubscriptionName,
Namespace: WebTerminalOperatorNamespace,
},
subscription); err != nil {
if apierrors.IsNotFound(err) {
return nil
}
return err
}
return errors.New("A non matching version of the Dev Workspace operator is already installed")
}
func createNamespace(deployContext *deploy.DeployContext) (bool, error) {
namespace := &corev1.Namespace{
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
APIVersion: corev1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: DevWorkspaceNamespace,
},
Spec: corev1.NamespaceSpec{},
}
return deploy.CreateIfNotExists(deployContext, namespace)
}
func syncServiceAccount(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceServiceAccountFile, &corev1.ServiceAccount{})
}
func syncRole(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceRoleFile, &rbacv1.Role{})
}
func syncRoleBinding(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceRoleBindingFile, &rbacv1.RoleBinding{})
}
func syncClusterRoleBinding(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceClusterRoleBindingFile, &rbacv1.ClusterRoleBinding{})
}
func syncProxyClusterRoleBinding(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceProxyClusterRoleBindingFile, &rbacv1.ClusterRoleBinding{})
}
func syncClusterRole(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceClusterRoleFile, &rbacv1.ClusterRole{})
}
func syncProxyClusterRole(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceProxyClusterRoleFile, &rbacv1.ClusterRole{})
}
func syncViewWorkspacesClusterRole(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceViewWorkspacesClusterRoleFile, &rbacv1.ClusterRole{})
}
func syncEditWorkspacesClusterRole(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceEditWorkspacesClusterRoleFile, &rbacv1.ClusterRole{})
}
func syncWorkspaceRoutingCRD(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceWorkspaceRoutingCRDFile, &apiextensionsv1.CustomResourceDefinition{})
}
func syncTemplatesCRD(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceTemplatesCRDFile, &apiextensionsv1.CustomResourceDefinition{})
}
func syncComponentsCRD(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceComponentsCRDFile, &apiextensionsv1.CustomResourceDefinition{})
}
func syncCRD(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceCRDFile, &apiextensionsv1.CustomResourceDefinition{})
}
func syncConfigMap(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceConfigMapFile, &corev1.ConfigMap{})
}
func syncDeployment(deployContext *deploy.DeployContext) (bool, error) {
return syncObject(deployContext, DevWorkspaceDeploymentFile, &appsv1.Deployment{})
}
func syncObject(deployContext *deploy.DeployContext, yamlFile string, obj interface{}) (bool, error) {
_, exists := cachedObj[yamlFile]
if !exists {
if err := util.ReadObject(yamlFile, obj); err != nil {
return false, err
}
cachedObj[yamlFile] = obj.(metav1.Object)
}
objectMeta := cachedObj[yamlFile]
return deploy.CreateIfNotExists(deployContext, objectMeta)
}

View File

@ -0,0 +1,115 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devworkspace
import (
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/eclipse/che-operator/pkg/deploy"
"github.com/eclipse/che-operator/pkg/util"
operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
func TestReconcileDevWorkspace(t *testing.T) {
scheme := scheme.Scheme
orgv1.SchemeBuilder.AddToScheme(scheme)
scheme.AddKnownTypes(operatorsv1alpha1.SchemeGroupVersion, &operatorsv1alpha1.Subscription{})
cli := fake.NewFakeClientWithScheme(scheme)
deployContext := &deploy.DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
Spec: orgv1.CheClusterSpec{
DevWorkspace: orgv1.CheClusterSpecDevWorkspace{
Enable: true,
},
Auth: orgv1.CheClusterSpecAuth{
OpenShiftoAuth: util.NewBoolPointer(true),
},
},
},
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme,
},
}
util.IsOpenShift4 = true
done, err := ReconcileDevWorkspace(deployContext)
if err != nil {
t.Fatalf("Error: %v", err)
}
if !done {
t.Fatalf("Dev Workspace operator has not been provisioned")
}
}
func TestReconcileDevWorkspaceShouldThrowErrorIfWebTerminalSubscriptionExists(t *testing.T) {
subscription := &operatorsv1alpha1.Subscription{
ObjectMeta: metav1.ObjectMeta{
Name: WebTerminalOperatorSubscriptionName,
Namespace: WebTerminalOperatorNamespace,
},
Spec: &operatorsv1alpha1.SubscriptionSpec{},
}
webhook := admissionregistrationv1.MutatingWebhookConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: DevWorkspaceWebhookName,
},
}
scheme := scheme.Scheme
orgv1.SchemeBuilder.AddToScheme(scheme)
scheme.AddKnownTypes(operatorsv1alpha1.SchemeGroupVersion, &operatorsv1alpha1.Subscription{})
scheme.AddKnownTypes(admissionregistrationv1.SchemeGroupVersion, &admissionregistrationv1.MutatingWebhookConfiguration{})
cli := fake.NewFakeClientWithScheme(scheme, subscription, &webhook)
deployContext := &deploy.DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
Spec: orgv1.CheClusterSpec{
DevWorkspace: orgv1.CheClusterSpecDevWorkspace{
Enable: true,
},
Auth: orgv1.CheClusterSpecAuth{
OpenShiftoAuth: util.NewBoolPointer(true),
},
},
},
ClusterAPI: deploy.ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme,
},
}
util.IsOpenShift4 = true
_, err := ReconcileDevWorkspace(deployContext)
if err == nil || err.Error() != "A non matching version of the Dev Workspace operator is already installed" {
t.Fatalf("Error should be thrown")
}
}

View File

@ -0,0 +1,21 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package devworkspace
import "github.com/eclipse/che-operator/pkg/deploy"
func init() {
err := deploy.InitTestDefaultsFromDeployment("../../../deploy/operator.yaml")
if err != nil {
panic(err)
}
}

View File

@ -1,3 +1,14 @@
//
// Copyright (c) 2020-2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package deploy
import (

View File

@ -85,6 +85,7 @@ type CheConfigMap struct {
ServerStrategy string `json:"CHE_INFRA_KUBERNETES_SERVER__STRATEGY"`
WorkspaceExposure string `json:"CHE_INFRA_KUBERNETES_SINGLEHOST_WORKSPACE_EXPOSURE"`
SingleHostGatewayConfigMapLabels string `json:"CHE_INFRA_KUBERNETES_SINGLEHOST_GATEWAY_CONFIGMAP__LABELS"`
CheDevWorkspacesEnabled string `json:"CHE_DEVWORKSPACES_ENABLED"`
}
func SyncCheConfigMapToCluster(deployContext *deploy.DeployContext) (*corev1.ConfigMap, error) {
@ -261,6 +262,7 @@ func GetCheConfigMapData(deployContext *deploy.DeployContext) (cheEnv map[string
ServerStrategy: ingressStrategy,
WorkspaceExposure: workspaceExposure,
SingleHostGatewayConfigMapLabels: singleHostGatewayConfigMapLabels,
CheDevWorkspacesEnabled: strconv.FormatBool(deployContext.CheCluster.Spec.DevWorkspace.Enable),
}
if cheMultiUser == "true" {

View File

@ -16,70 +16,88 @@ import (
// Sync syncs the blueprint to the cluster in a generic (as much as Go allows) manner.
// Returns true if the object was created or updated, false if there was no change detected.
func Sync(deployContext *DeployContext, blueprint metav1.Object, diffOpts cmp.Option) (bool, error) {
key := client.ObjectKey{Name: blueprint.GetName(), Namespace: blueprint.GetNamespace()}
actual, err := Get(deployContext, key, blueprint)
if err != nil {
return false, err
}
if actual == nil {
return Create(deployContext, key, blueprint)
}
return Update(deployContext, *actual, blueprint, diffOpts)
}
func CreateIfNotExists(deployContext *DeployContext, objectMeta metav1.Object) (bool, error) {
key := client.ObjectKey{Name: objectMeta.GetName(), Namespace: objectMeta.GetNamespace()}
exists, err := IsExists(deployContext, key, objectMeta)
if err != nil {
return false, err
}
if !exists {
return Create(deployContext, key, objectMeta)
}
return true, nil
}
// Indicates if objects exists
func IsExists(deployContext *DeployContext, key client.ObjectKey, objectMeta metav1.Object) (bool, error) {
actualObject, err := Get(deployContext, key, objectMeta)
return actualObject != nil, err
}
// Gets object by key
func Get(deployContext *DeployContext, key client.ObjectKey, objectMeta metav1.Object) (*runtime.Object, error) {
runtimeObject, ok := objectMeta.(runtime.Object)
if !ok {
return nil, fmt.Errorf("object %T is not a runtime.Object. Cannot sync it", runtimeObject)
}
client := getClientForObject(objectMeta, deployContext)
actual := runtimeObject.DeepCopyObject()
err := client.Get(context.TODO(), key, actual)
if err != nil {
if errors.IsNotFound(err) {
return nil, nil
}
return nil, err
}
return &actual, nil
}
func Create(deployContext *DeployContext, key client.ObjectKey, blueprint metav1.Object) (bool, error) {
blueprintObject, ok := blueprint.(runtime.Object)
if !ok {
return false, fmt.Errorf("object %T is not a runtime.Object. Cannot sync it", blueprint)
}
key := client.ObjectKey{Name: blueprint.GetName(), Namespace: blueprint.GetNamespace()}
actual := blueprintObject.DeepCopyObject()
if getErr := deployContext.ClusterAPI.Client.Get(context.TODO(), key, actual); getErr != nil {
if statusErr, ok := getErr.(*errors.StatusError); !ok || statusErr.Status().Reason != metav1.StatusReasonNotFound {
return false, getErr
}
actual = nil
}
if actual == nil {
_, err := create(deployContext, key, blueprint)
if err != nil {
return false, err
}
return true, nil
}
return update(deployContext, actual, blueprint, diffOpts)
}
func create(deployContext *DeployContext, key client.ObjectKey, blueprint metav1.Object) (runtime.Object, error) {
blueprintObject, ok := blueprint.(runtime.Object)
kind := blueprintObject.GetObjectKind().GroupVersionKind().Kind
if !ok {
return nil, fmt.Errorf("object %T is not a runtime.Object. Cannot sync it", blueprint)
}
actual := blueprintObject.DeepCopyObject()
clusterAPI := deployContext.ClusterAPI
logrus.Infof("Creating a new object: %s, name %s", kind, blueprint.GetName())
obj, err := setOwnerReferenceAndConvertToRuntime(deployContext, blueprint)
if err != nil {
return nil, err
return false, err
}
err = clusterAPI.Client.Create(context.TODO(), obj)
client := getClientForObject(blueprint, deployContext)
err = client.Create(context.TODO(), obj)
if err != nil {
if !errors.IsAlreadyExists(err) {
return nil, err
}
// ok, we got an already-exists error. So let's try to load the object into "actual".
// if we fail this retry for whatever reason, just give up rather than retrying this in a loop...
// the reconciliation loop will lead us here again in the next round.
if getErr := deployContext.ClusterAPI.Client.Get(context.TODO(), key, actual); getErr != nil {
return nil, getErr
if errors.IsAlreadyExists(err) {
return false, nil
}
return false, err
}
return actual, nil
return true, nil
}
func update(deployContext *DeployContext, actual runtime.Object, blueprint metav1.Object, diffOpts cmp.Option) (bool, error) {
clusterAPI := deployContext.ClusterAPI
func Update(deployContext *DeployContext, actual runtime.Object, blueprint metav1.Object, diffOpts cmp.Option) (bool, error) {
client := getClientForObject(blueprint, deployContext)
actualMeta := actual.(metav1.Object)
diff := cmp.Diff(actual, blueprint, diffOpts)
@ -89,7 +107,7 @@ func update(deployContext *DeployContext, actual runtime.Object, blueprint metav
fmt.Printf("Difference:\n%s", diff)
if isUpdateUsingDeleteCreate(actual.GetObjectKind().GroupVersionKind().Kind) {
err := clusterAPI.Client.Delete(context.TODO(), actual)
err := client.Delete(context.TODO(), actual)
if err != nil {
return false, err
}
@ -99,7 +117,7 @@ func update(deployContext *DeployContext, actual runtime.Object, blueprint metav
return false, err
}
err = clusterAPI.Client.Create(context.TODO(), obj)
err = client.Create(context.TODO(), obj)
return false, err
} else {
obj, err := setOwnerReferenceAndConvertToRuntime(deployContext, blueprint)
@ -110,7 +128,7 @@ func update(deployContext *DeployContext, actual runtime.Object, blueprint metav
// to be able to update, we need to set the resource version of the object that we know of
obj.(metav1.Object).SetResourceVersion(actualMeta.GetResourceVersion())
err = clusterAPI.Client.Update(context.TODO(), obj)
err = client.Update(context.TODO(), obj)
return false, err
}
}
@ -121,17 +139,13 @@ func isUpdateUsingDeleteCreate(kind string) bool {
return "Service" == kind || "Ingress" == kind || "Route" == kind
}
func shouldSetOwnerReference(kind string) bool {
return "OAuthClient" != kind
}
func setOwnerReferenceAndConvertToRuntime(deployContext *DeployContext, obj metav1.Object) (runtime.Object, error) {
robj, ok := obj.(runtime.Object)
if !ok {
return nil, fmt.Errorf("object %T is not a runtime.Object. Cannot sync it", obj)
}
if !shouldSetOwnerReference(robj.GetObjectKind().GroupVersionKind().Kind) {
if !shouldSetOwnerReferenceForObject(deployContext, obj) {
return robj, nil
}
@ -142,3 +156,16 @@ func setOwnerReferenceAndConvertToRuntime(deployContext *DeployContext, obj meta
return robj, nil
}
func shouldSetOwnerReferenceForObject(deployContext *DeployContext, obj metav1.Object) bool {
// empty workspace (cluster scope object) or object in another namespace
return obj.GetNamespace() == deployContext.CheCluster.Namespace
}
func getClientForObject(objectMeta metav1.Object, deployContext *DeployContext) client.Client {
// empty namespace (cluster scope object) or object in another namespace
if deployContext.CheCluster.Namespace == objectMeta.GetNamespace() {
return deployContext.ClusterAPI.Client
}
return deployContext.ClusterAPI.NonCachedClient
}

313
pkg/deploy/sync_test.go Normal file
View File

@ -0,0 +1,313 @@
//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package deploy
import (
"context"
orgv1 "github.com/eclipse/che-operator/pkg/apis/org/v1"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"testing"
)
func TestGet(t *testing.T) {
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
err := cli.Create(context.TODO(), secret)
if err != nil {
t.Fatalf("Error creating object: %v", err)
}
actual, err := Get(deployContext,
client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"},
&corev1.Secret{})
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
if actual == nil {
t.Fatalf("Object not found")
}
}
func TestIsExists(t *testing.T) {
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
err := cli.Create(context.TODO(), secret)
if err != nil {
t.Fatalf("Error creating object: %v", err)
}
exists, err := IsExists(deployContext,
client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"},
&corev1.Secret{})
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
if !exists {
t.Fatalf("Object not found")
}
}
func TestCreate(t *testing.T) {
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
done, err := Create(deployContext,
client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"},
secret)
if err != nil {
t.Fatalf("Error creating object: %v", err)
}
if !done {
t.Fatalf("Object was not created")
}
actual := &corev1.Secret{}
err = cli.Get(context.TODO(), client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"}, actual)
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
if actual == nil {
t.Fatalf("Object not found")
}
}
func TestUpdate(t *testing.T) {
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
},
}
newSecret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
Labels: map[string]string{"a": "b"},
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
err := cli.Create(context.TODO(), secret)
if err != nil {
t.Fatalf("Error creating object: %v", err)
}
actual := &corev1.Secret{}
err = cli.Get(context.TODO(), client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"}, actual)
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
_, err = Update(deployContext, actual, newSecret, cmp.Options{})
if err != nil {
t.Fatalf("Error updating object: %v", err)
}
newActual := &corev1.Secret{}
err = cli.Get(context.TODO(), client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"}, newActual)
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
if actual == nil {
t.Fatalf("Object not found")
}
if newActual.Labels["a"] != "b" {
t.Fatalf("Object was not updated properly")
}
}
func TestSync(t *testing.T) {
secret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
},
}
newSecret := &corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test-secret",
Namespace: "eclipse-che",
Labels: map[string]string{"a": "b"},
},
}
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
cli := fake.NewFakeClientWithScheme(scheme.Scheme)
deployContext := &DeployContext{
CheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
ClusterAPI: ClusterAPI{
Client: cli,
NonCachedClient: cli,
Scheme: scheme.Scheme,
},
}
err := cli.Create(context.TODO(), secret)
if err != nil {
t.Fatalf("Error creating object: %v", err)
}
actual := &corev1.Secret{}
err = cli.Get(context.TODO(), client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"}, actual)
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
_, err = Sync(deployContext, newSecret, cmp.Options{})
if err != nil {
t.Fatalf("Error syncing object: %v", err)
}
newActual := &corev1.Secret{}
err = cli.Get(context.TODO(), client.ObjectKey{Name: "test-secret", Namespace: "eclipse-che"}, newActual)
if err != nil {
t.Fatalf("Error getting object: %v", err)
}
if actual == nil {
t.Fatalf("Object not found")
}
if newActual.Labels["a"] != "b" {
t.Fatalf("Object was not synced properly")
}
}

View File

@ -36,6 +36,7 @@ import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/yaml"
)
var (
@ -421,3 +422,17 @@ func FindEnv(envs []corev1.EnvVar, name string) *corev1.EnvVar {
return nil
}
func ReadObject(yamlFile string, obj interface{}) error {
data, err := ioutil.ReadFile(yamlFile)
if err != nil {
return err
}
err = yaml.Unmarshal(data, obj)
if err != nil {
return err
}
return nil
}

18
vendor/gopkg.in/yaml.v2/.travis.yml generated vendored
View File

@ -1,16 +1,12 @@
language: go
go:
- "1.4.x"
- "1.5.x"
- "1.6.x"
- "1.7.x"
- "1.8.x"
- "1.9.x"
- "1.10.x"
- "1.11.x"
- "1.12.x"
- "1.13.x"
- "tip"
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
go_import_path: gopkg.in/yaml.v2

105
vendor/gopkg.in/yaml.v2/scannerc.go generated vendored
View File

@ -626,17 +626,30 @@ func trace(args ...interface{}) func() {
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
// While we need more tokens to fetch, do it.
for {
if parser.tokens_head != len(parser.tokens) {
// If queue is non-empty, check if any potential simple key may
// occupy the head position.
head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
if !ok {
break
} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
// Check if we really need to fetch more tokens.
need_more_tokens := false
if parser.tokens_head == len(parser.tokens) {
// Queue is empty.
need_more_tokens = true
} else {
// Check if any potential simple key may occupy the head position.
if !yaml_parser_stale_simple_keys(parser) {
return false
} else if !valid {
break
}
for i := range parser.simple_keys {
simple_key := &parser.simple_keys[i]
if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
need_more_tokens = true
break
}
}
}
// We are finished.
if !need_more_tokens {
break
}
// Fetch the next token.
if !yaml_parser_fetch_next_token(parser) {
@ -665,6 +678,11 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
return false
}
// Remove obsolete potential simple keys.
if !yaml_parser_stale_simple_keys(parser) {
return false
}
// Check the indentation level against the current column.
if !yaml_parser_unroll_indent(parser, parser.mark.column) {
return false
@ -819,30 +837,29 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
"found character that cannot start any token")
}
func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
if !simple_key.possible {
return false, true
}
// Check the list of potential simple keys and remove the positions that
// cannot contain simple keys anymore.
func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
// Check for a potential simple key for each flow level.
for i := range parser.simple_keys {
simple_key := &parser.simple_keys[i]
// The 1.2 specification says:
//
// "If the ? indicator is omitted, parsing needs to see past the
// implicit key to recognize it as such. To limit the amount of
// lookahead required, the “:” indicator must appear at most 1024
// Unicode characters beyond the start of the key. In addition, the key
// is restricted to a single line."
//
if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
// Check if the potential simple key to be removed is required.
if simple_key.required {
return false, yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key.mark,
"could not find expected ':'")
// The specification requires that a simple key
//
// - is limited to a single line,
// - is shorter than 1024 characters.
if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
// Check if the potential simple key to be removed is required.
if simple_key.required {
return yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key.mark,
"could not find expected ':'")
}
simple_key.possible = false
}
simple_key.possible = false
return false, true
}
return true, true
return true
}
// Check if a simple key may start at the current position and add it if
@ -862,14 +879,13 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
possible: true,
required: required,
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
mark: parser.mark,
}
simple_key.mark = parser.mark
if !yaml_parser_remove_simple_key(parser) {
return false
}
parser.simple_keys[len(parser.simple_keys)-1] = simple_key
parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
}
return true
}
@ -884,10 +900,9 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
"while scanning a simple key", parser.simple_keys[i].mark,
"could not find expected ':'")
}
// Remove the key from the stack.
parser.simple_keys[i].possible = false
delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
}
// Remove the key from the stack.
parser.simple_keys[i].possible = false
return true
}
@ -897,12 +912,7 @@ const max_flow_level = 10000
// Increase the flow level and resize the simple key list if needed.
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
// Reset the simple key on the next level.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
possible: false,
required: false,
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
mark: parser.mark,
})
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
// Increase the flow level.
parser.flow_level++
@ -918,9 +928,7 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
if parser.flow_level > 0 {
parser.flow_level--
last := len(parser.simple_keys) - 1
delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
parser.simple_keys = parser.simple_keys[:last]
parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
}
return true
}
@ -997,8 +1005,6 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
// Initialize the simple key stack.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
parser.simple_keys_by_tok = make(map[int]int)
// A simple key is allowed at the beginning of the stream.
parser.simple_key_allowed = true
@ -1280,11 +1286,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
// Have we found a simple key?
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
return false
} else if valid {
if simple_key.possible {
// Create the KEY token and insert it into the queue.
token := yaml_token_t{
typ: yaml_KEY_TOKEN,
@ -1302,7 +1304,6 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
// Remove the simple key.
simple_key.possible = false
delete(parser.simple_keys_by_tok, simple_key.token_number)
// A simple key cannot follow another simple key.
parser.simple_key_allowed = false

2
vendor/gopkg.in/yaml.v2/yaml.go generated vendored
View File

@ -89,7 +89,7 @@ func UnmarshalStrict(in []byte, out interface{}) (err error) {
return unmarshal(in, out, true)
}
// A Decoder reads and decodes YAML values from an input stream.
// A Decorder reads and decodes YAML values from an input stream.
type Decoder struct {
strict bool
parser *parser

1
vendor/gopkg.in/yaml.v2/yamlh.go generated vendored
View File

@ -579,7 +579,6 @@ type yaml_parser_t struct {
simple_key_allowed bool // May a simple key occur at the current position?
simple_keys []yaml_simple_key_t // The stack of simple keys.
simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
// Parser stuff

202
vendor/k8s.io/apiextensions-apiserver/LICENSE generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,288 @@
/*
Copyright 2017 The Kubernetes 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 apiextensions
import "k8s.io/apimachinery/pkg/runtime"
// TODO: Update this after a tag is created for interface fields in DeepCopy
func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
if in == nil {
return nil
}
out := new(JSONSchemaProps)
*out = *in
if in.Default != nil {
defaultJSON := JSON(runtime.DeepCopyJSONValue(*(in.Default)))
out.Default = &(defaultJSON)
} else {
out.Default = nil
}
if in.Example != nil {
exampleJSON := JSON(runtime.DeepCopyJSONValue(*(in.Example)))
out.Example = &(exampleJSON)
} else {
out.Example = nil
}
if in.Ref != nil {
in, out := &in.Ref, &out.Ref
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
}
if in.Maximum != nil {
in, out := &in.Maximum, &out.Maximum
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.Minimum != nil {
in, out := &in.Minimum, &out.Minimum
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.MaxLength != nil {
in, out := &in.MaxLength, &out.MaxLength
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinLength != nil {
in, out := &in.MinLength, &out.MinLength
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MaxItems != nil {
in, out := &in.MaxItems, &out.MaxItems
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinItems != nil {
in, out := &in.MinItems, &out.MinItems
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MultipleOf != nil {
in, out := &in.MultipleOf, &out.MultipleOf
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.Enum != nil {
out.Enum = make([]JSON, len(in.Enum))
for i := range in.Enum {
out.Enum[i] = runtime.DeepCopyJSONValue(in.Enum[i])
}
}
if in.MaxProperties != nil {
in, out := &in.MaxProperties, &out.MaxProperties
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinProperties != nil {
in, out := &in.MinProperties, &out.MinProperties
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.Required != nil {
in, out := &in.Required, &out.Required
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Items != nil {
in, out := &in.Items, &out.Items
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrArray)
(*in).DeepCopyInto(*out)
}
}
if in.AllOf != nil {
in, out := &in.AllOf, &out.AllOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.OneOf != nil {
in, out := &in.OneOf, &out.OneOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AnyOf != nil {
in, out := &in.AnyOf, &out.AnyOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Not != nil {
in, out := &in.Not, &out.Not
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaProps)
(*in).DeepCopyInto(*out)
}
}
if in.Properties != nil {
in, out := &in.Properties, &out.Properties
*out = make(map[string]JSONSchemaProps, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.AdditionalProperties != nil {
in, out := &in.AdditionalProperties, &out.AdditionalProperties
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrBool)
(*in).DeepCopyInto(*out)
}
}
if in.PatternProperties != nil {
in, out := &in.PatternProperties, &out.PatternProperties
*out = make(map[string]JSONSchemaProps, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Dependencies != nil {
in, out := &in.Dependencies, &out.Dependencies
*out = make(JSONSchemaDependencies, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.AdditionalItems != nil {
in, out := &in.AdditionalItems, &out.AdditionalItems
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrBool)
(*in).DeepCopyInto(*out)
}
}
if in.Definitions != nil {
in, out := &in.Definitions, &out.Definitions
*out = make(JSONSchemaDefinitions, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.ExternalDocs != nil {
in, out := &in.ExternalDocs, &out.ExternalDocs
if *in == nil {
*out = nil
} else {
*out = new(ExternalDocumentation)
(*in).DeepCopyInto(*out)
}
}
if in.XPreserveUnknownFields != nil {
in, out := &in.XPreserveUnknownFields, &out.XPreserveUnknownFields
if *in == nil {
*out = nil
} else {
*out = new(bool)
**out = **in
}
}
if in.XListMapKeys != nil {
in, out := &in.XListMapKeys, &out.XListMapKeys
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.XListType != nil {
in, out := &in.XListType, &out.XListType
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
}
return out
}

View File

@ -0,0 +1,21 @@
/*
Copyright 2017 The Kubernetes 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.
*/
// +k8s:deepcopy-gen=package
// +groupName=apiextensions.k8s.io
// Package apiextensions is the internal version of the API.
package apiextensions // import "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"

View File

@ -0,0 +1,257 @@
/*
Copyright 2017 The Kubernetes 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 apiextensions
import (
"fmt"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
// SetCRDCondition sets the status condition. It either overwrites the existing one or creates a new one.
func SetCRDCondition(crd *CustomResourceDefinition, newCondition CustomResourceDefinitionCondition) {
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
existingCondition := FindCRDCondition(crd, newCondition.Type)
if existingCondition == nil {
crd.Status.Conditions = append(crd.Status.Conditions, newCondition)
return
}
if existingCondition.Status != newCondition.Status || existingCondition.LastTransitionTime.IsZero() {
existingCondition.LastTransitionTime = newCondition.LastTransitionTime
}
existingCondition.Status = newCondition.Status
existingCondition.Reason = newCondition.Reason
existingCondition.Message = newCondition.Message
}
// RemoveCRDCondition removes the status condition.
func RemoveCRDCondition(crd *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) {
newConditions := []CustomResourceDefinitionCondition{}
for _, condition := range crd.Status.Conditions {
if condition.Type != conditionType {
newConditions = append(newConditions, condition)
}
}
crd.Status.Conditions = newConditions
}
// FindCRDCondition returns the condition you're looking for or nil.
func FindCRDCondition(crd *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) *CustomResourceDefinitionCondition {
for i := range crd.Status.Conditions {
if crd.Status.Conditions[i].Type == conditionType {
return &crd.Status.Conditions[i]
}
}
return nil
}
// IsCRDConditionTrue indicates if the condition is present and strictly true.
func IsCRDConditionTrue(crd *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) bool {
return IsCRDConditionPresentAndEqual(crd, conditionType, ConditionTrue)
}
// IsCRDConditionFalse indicates if the condition is present and false.
func IsCRDConditionFalse(crd *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) bool {
return IsCRDConditionPresentAndEqual(crd, conditionType, ConditionFalse)
}
// IsCRDConditionPresentAndEqual indicates if the condition is present and equal to the given status.
func IsCRDConditionPresentAndEqual(crd *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType, status ConditionStatus) bool {
for _, condition := range crd.Status.Conditions {
if condition.Type == conditionType {
return condition.Status == status
}
}
return false
}
// IsCRDConditionEquivalent returns true if the lhs and rhs are equivalent except for times.
func IsCRDConditionEquivalent(lhs, rhs *CustomResourceDefinitionCondition) bool {
if lhs == nil && rhs == nil {
return true
}
if lhs == nil || rhs == nil {
return false
}
return lhs.Message == rhs.Message && lhs.Reason == rhs.Reason && lhs.Status == rhs.Status && lhs.Type == rhs.Type
}
// CRDHasFinalizer returns true if the finalizer is in the list.
func CRDHasFinalizer(crd *CustomResourceDefinition, needle string) bool {
for _, finalizer := range crd.Finalizers {
if finalizer == needle {
return true
}
}
return false
}
// CRDRemoveFinalizer removes the finalizer if present.
func CRDRemoveFinalizer(crd *CustomResourceDefinition, needle string) {
newFinalizers := []string{}
for _, finalizer := range crd.Finalizers {
if finalizer != needle {
newFinalizers = append(newFinalizers, finalizer)
}
}
crd.Finalizers = newFinalizers
}
// HasServedCRDVersion returns true if the given version is in the list of CRD's versions and the Served flag is set.
func HasServedCRDVersion(crd *CustomResourceDefinition, version string) bool {
for _, v := range crd.Spec.Versions {
if v.Name == version {
return v.Served
}
}
return false
}
// GetCRDStorageVersion returns the storage version for given CRD.
func GetCRDStorageVersion(crd *CustomResourceDefinition) (string, error) {
for _, v := range crd.Spec.Versions {
if v.Storage {
return v.Name, nil
}
}
// This should not happened if crd is valid
return "", fmt.Errorf("invalid CustomResourceDefinition, no storage version")
}
// IsStoredVersion returns whether the given version is the storage version of the CRD.
func IsStoredVersion(crd *CustomResourceDefinition, version string) bool {
for _, v := range crd.Status.StoredVersions {
if version == v {
return true
}
}
return false
}
// GetSchemaForVersion returns the validation schema for the given version or nil.
func GetSchemaForVersion(crd *CustomResourceDefinition, version string) (*CustomResourceValidation, error) {
if !HasPerVersionSchema(crd.Spec.Versions) {
return crd.Spec.Validation, nil
}
if crd.Spec.Validation != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version schemas must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Schema, nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// GetSubresourcesForVersion returns the subresources for given version or nil.
func GetSubresourcesForVersion(crd *CustomResourceDefinition, version string) (*CustomResourceSubresources, error) {
if !HasPerVersionSubresources(crd.Spec.Versions) {
return crd.Spec.Subresources, nil
}
if crd.Spec.Subresources != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version subresources must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Subresources, nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// GetColumnsForVersion returns the columns for given version or nil.
// NOTE: the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func GetColumnsForVersion(crd *CustomResourceDefinition, version string) ([]CustomResourceColumnDefinition, error) {
if !HasPerVersionColumns(crd.Spec.Versions) {
return serveDefaultColumnsIfEmpty(crd.Spec.AdditionalPrinterColumns), nil
}
if len(crd.Spec.AdditionalPrinterColumns) > 0 {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version additionalPrinterColumns must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return serveDefaultColumnsIfEmpty(v.AdditionalPrinterColumns), nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// HasPerVersionSchema returns true if a CRD uses per-version schema.
func HasPerVersionSchema(versions []CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Schema != nil {
return true
}
}
return false
}
// HasPerVersionSubresources returns true if a CRD uses per-version subresources.
func HasPerVersionSubresources(versions []CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Subresources != nil {
return true
}
}
return false
}
// HasPerVersionColumns returns true if a CRD uses per-version columns.
func HasPerVersionColumns(versions []CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}
// serveDefaultColumnsIfEmpty applies logically defaulting to columns, if the input columns is empty.
// NOTE: in this way, the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func serveDefaultColumnsIfEmpty(columns []CustomResourceColumnDefinition) []CustomResourceColumnDefinition {
if len(columns) > 0 {
return columns
}
return []CustomResourceColumnDefinition{
{Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
}
}
// HasVersionServed returns true if given CRD has given version served.
func HasVersionServed(crd *CustomResourceDefinition, version string) bool {
for _, v := range crd.Spec.Versions {
if !v.Served || v.Name != version {
continue
}
return true
}
return false
}

View File

@ -0,0 +1,51 @@
/*
Copyright 2017 The Kubernetes 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 apiextensions
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const GroupName = "apiextensions.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
AddToScheme = SchemeBuilder.AddToScheme
)
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CustomResourceDefinition{},
&CustomResourceDefinitionList{},
)
return nil
}

View File

@ -0,0 +1,411 @@
/*
Copyright 2017 The Kubernetes 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 apiextensions
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// ConversionStrategyType describes different conversion types.
type ConversionStrategyType string
const (
// NoneConverter is a converter that only sets apiversion of the CR and leave everything else unchanged.
NoneConverter ConversionStrategyType = "None"
// WebhookConverter is a converter that calls to an external webhook to convert the CR.
WebhookConverter ConversionStrategyType = "Webhook"
)
// CustomResourceDefinitionSpec describes how a user wants their resource to appear
type CustomResourceDefinitionSpec struct {
// Group is the group this resource belongs in
Group string
// Version is the version this resource belongs in
// Should be always first item in Versions field if provided.
// Optional, but at least one of Version or Versions must be set.
// Deprecated: Please use `Versions`.
Version string
// Names are the names used to describe this custom resource
Names CustomResourceDefinitionNames
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
Scope ResourceScope
// Validation describes the validation methods for CustomResources
// Optional, the global validation schema for all versions.
// Top-level and per-version schemas are mutually exclusive.
// +optional
Validation *CustomResourceValidation
// Subresources describes the subresources for CustomResource
// Optional, the global subresources for all versions.
// Top-level and per-version subresources are mutually exclusive.
// +optional
Subresources *CustomResourceSubresources
// Versions is the list of all supported versions for this resource.
// If Version field is provided, this field is optional.
// Validation: All versions must use the same validation schema for now. i.e., top
// level Validation field is applied to all of these versions.
// Order: The version name will be used to compute the order.
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
// then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
// major version, then minor version. An example sorted list of versions:
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
Versions []CustomResourceDefinitionVersion
// AdditionalPrinterColumns are additional columns shown e.g. in kubectl next to the name. Defaults to a created-at column.
// Optional, the global columns for all versions.
// Top-level and per-version columns are mutually exclusive.
// +optional
AdditionalPrinterColumns []CustomResourceColumnDefinition
// `conversion` defines conversion settings for the CRD.
Conversion *CustomResourceConversion
// preserveUnknownFields disables pruning of object fields which are not
// specified in the OpenAPI schema. apiVersion, kind, metadata and known
// fields inside metadata are always preserved.
// Defaults to true in v1beta and will default to false in v1.
PreserveUnknownFields *bool
}
// CustomResourceConversion describes how to convert different versions of a CR.
type CustomResourceConversion struct {
// `strategy` specifies the conversion strategy. Allowed values are:
// - `None`: The converter only change the apiVersion and would not touch any other field in the CR.
// - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information
// is needed for this option. This requires spec.preserveUnknownFields to be false.
Strategy ConversionStrategyType
// `webhookClientConfig` is the instructions for how to call the webhook if strategy is `Webhook`.
WebhookClientConfig *WebhookClientConfig
// ConversionReviewVersions is an ordered list of preferred `ConversionReview`
// versions the Webhook expects. API server will try to use first version in
// the list which it supports. If none of the versions specified in this list
// supported by API server, conversion will fail for this object.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
// +optional
ConversionReviewVersions []string
}
// WebhookClientConfig contains the information to make a TLS
// connection with the webhook. It has the same field as admissionregistration.internal.WebhookClientConfig.
type WebhookClientConfig struct {
// `url` gives the location of the webhook, in standard URL form
// (`scheme://host:port/path`). Exactly one of `url` or `service`
// must be specified.
//
// The `host` should not refer to a service running in the cluster; use
// the `service` field instead. The host might be resolved via external
// DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
// in-cluster DNS as that would be a layering violation). `host` may
// also be an IP address.
//
// Please note that using `localhost` or `127.0.0.1` as a `host` is
// risky unless you take great care to run this webhook on all hosts
// which run an apiserver which might need to make calls to this
// webhook. Such installs are likely to be non-portable, i.e., not easy
// to turn up in a new cluster.
//
// The scheme must be "https"; the URL must begin with "https://".
//
// A path is optional, and if present may be any string permissible in
// a URL. You may use the path to pass an arbitrary string to the
// webhook, for example, a cluster identifier.
//
// Attempting to use a user or basic auth e.g. "user:password@" is not
// allowed. Fragments ("#...") and query parameters ("?...") are not
// allowed, either.
//
// +optional
URL *string
// `service` is a reference to the service for this webhook. Either
// `service` or `url` must be specified.
//
// If the webhook is running within the cluster, then you should use `service`.
//
// +optional
Service *ServiceReference
// `caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
// If unspecified, system trust roots on the apiserver are used.
// +optional
CABundle []byte
}
// ServiceReference holds a reference to Service.legacy.k8s.io
type ServiceReference struct {
// `namespace` is the namespace of the service.
// Required
Namespace string
// `name` is the name of the service.
// Required
Name string
// `path` is an optional URL path which will be sent in any request to
// this service.
// +optional
Path *string
// If specified, the port on the service that hosting webhook.
// `port` should be a valid port number (1-65535, inclusive).
// +optional
Port int32
}
// CustomResourceDefinitionVersion describes a version for CRD.
type CustomResourceDefinitionVersion struct {
// Name is the version name, e.g. “v1”, “v2beta1”, etc.
Name string
// Served is a flag enabling/disabling this version from being served via REST APIs
Served bool
// Storage flags the version as storage version. There must be exactly one flagged
// as storage version.
Storage bool
// Schema describes the schema for CustomResource used in validation, pruning, and defaulting.
// Top-level and per-version schemas are mutually exclusive.
// Per-version schemas must not all be set to identical values (top-level validation schema should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
Schema *CustomResourceValidation
// Subresources describes the subresources for CustomResource
// Top-level and per-version subresources are mutually exclusive.
// Per-version subresources must not all be set to identical values (top-level subresources should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
Subresources *CustomResourceSubresources
// AdditionalPrinterColumns are additional columns shown e.g. in kubectl next to the name. Defaults to a created-at column.
// Top-level and per-version columns are mutually exclusive.
// Per-version columns must not all be set to identical values (top-level columns should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// NOTE: CRDs created prior to 1.13 populated the top-level additionalPrinterColumns field by default. To apply an
// update that changes to per-version additionalPrinterColumns, the top-level additionalPrinterColumns field must
// be explicitly set to null
// +optional
AdditionalPrinterColumns []CustomResourceColumnDefinition
}
// CustomResourceColumnDefinition specifies a column for server side printing.
type CustomResourceColumnDefinition struct {
// name is a human readable name for the column.
Name string
// type is an OpenAPI type definition for this column.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.
Type string
// format is an optional OpenAPI type definition for this column. The 'name' format is applied
// to the primary identifier column to assist in clients identifying column is the resource name.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.
Format string
// description is a human readable description of this column.
Description string
// priority is an integer defining the relative importance of this column compared to others. Lower
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
// should be given a higher priority.
Priority int32
// JSONPath is a simple JSON path, i.e. without array notation.
JSONPath string
}
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
type CustomResourceDefinitionNames struct {
// Plural is the plural name of the resource to serve. It must match the name of the CustomResourceDefinition-registration
// too: plural.group and it must be all lowercase.
Plural string
// Singular is the singular name of the resource. It must be all lowercase Defaults to lowercased <kind>
Singular string
// ShortNames are short names for the resource. It must be all lowercase.
ShortNames []string
// Kind is the serialized kind of the resource. It is normally CamelCase and singular.
Kind string
// ListKind is the serialized kind of the list for this resource. Defaults to <kind>List.
ListKind string
// Categories is a list of grouped resources custom resources belong to (e.g. 'all')
// +optional
Categories []string
}
// ResourceScope is an enum defining the different scopes available to a custom resource
type ResourceScope string
const (
ClusterScoped ResourceScope = "Cluster"
NamespaceScoped ResourceScope = "Namespaced"
)
type ConditionStatus string
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
// can't decide if a resource is in the condition or not. In the future, we could add other
// intermediate conditions, e.g. ConditionDegraded.
const (
ConditionTrue ConditionStatus = "True"
ConditionFalse ConditionStatus = "False"
ConditionUnknown ConditionStatus = "Unknown"
)
// CustomResourceDefinitionConditionType is a valid value for CustomResourceDefinitionCondition.Type
type CustomResourceDefinitionConditionType string
const (
// Established means that the resource has become active. A resource is established when all names are
// accepted without a conflict for the first time. A resource stays established until deleted, even during
// a later NamesAccepted due to changed names. Note that not all names can be changed.
Established CustomResourceDefinitionConditionType = "Established"
// NamesAccepted means the names chosen for this CustomResourceDefinition do not conflict with others in
// the group and are therefore accepted.
NamesAccepted CustomResourceDefinitionConditionType = "NamesAccepted"
// NonStructuralSchema means that one or more OpenAPI schema is not structural.
//
// A schema is structural if it specifies types for all values, with the only exceptions of those with
// - x-kubernetes-int-or-string: true — for fields which can be integer or string
// - x-kubernetes-preserve-unknown-fields: true — for raw, unspecified JSON values
// and there is no type, additionalProperties, default, nullable or x-kubernetes-* vendor extenions
// specified under allOf, anyOf, oneOf or not.
//
// Non-structural schemas will not be allowed anymore in v1 API groups. Moreover, new features will not be
// available for non-structural CRDs:
// - pruning
// - defaulting
// - read-only
// - OpenAPI publishing
// - webhook conversion
NonStructuralSchema CustomResourceDefinitionConditionType = "NonStructuralSchema"
// Terminating means that the CustomResourceDefinition has been deleted and is cleaning up.
Terminating CustomResourceDefinitionConditionType = "Terminating"
// KubernetesAPIApprovalPolicyConformant indicates that an API in *.k8s.io or *.kubernetes.io is or is not approved. For CRDs
// outside those groups, this condition will not be set. For CRDs inside those groups, the condition will
// be true if .metadata.annotations["api-approved.kubernetes.io"] is set to a URL, otherwise it will be false.
// See https://github.com/kubernetes/enhancements/pull/1111 for more details.
KubernetesAPIApprovalPolicyConformant CustomResourceDefinitionConditionType = "KubernetesAPIApprovalPolicyConformant"
)
// CustomResourceDefinitionCondition contains details for the current condition of this pod.
type CustomResourceDefinitionCondition struct {
// Type is the type of the condition. Types include Established, NamesAccepted and Terminating.
Type CustomResourceDefinitionConditionType
// Status is the status of the condition.
// Can be True, False, Unknown.
Status ConditionStatus
// Last time the condition transitioned from one status to another.
// +optional
LastTransitionTime metav1.Time
// Unique, one-word, CamelCase reason for the condition's last transition.
// +optional
Reason string
// Human-readable message indicating details about last transition.
// +optional
Message string
}
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
type CustomResourceDefinitionStatus struct {
// Conditions indicate state for particular aspects of a CustomResourceDefinition
Conditions []CustomResourceDefinitionCondition
// AcceptedNames are the names that are actually being used to serve discovery
// They may be different than the names in spec.
AcceptedNames CustomResourceDefinitionNames
// StoredVersions are all versions of CustomResources that were ever persisted. Tracking these
// versions allows a migration path for stored versions in etcd. The field is mutable
// so the migration controller can first finish a migration to another version (i.e.
// that no old objects are left in the storage), and then remove the rest of the
// versions from this list.
// None of the versions in this list can be removed from the spec.Versions field.
StoredVersions []string
}
// CustomResourceCleanupFinalizer is the name of the finalizer which will delete instances of
// a CustomResourceDefinition
const CustomResourceCleanupFinalizer = "customresourcecleanup.apiextensions.k8s.io"
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format
// <.spec.name>.<.spec.group>.
type CustomResourceDefinition struct {
metav1.TypeMeta
metav1.ObjectMeta
// Spec describes how the user wants the resources to appear
Spec CustomResourceDefinitionSpec
// Status indicates the actual state of the CustomResourceDefinition
Status CustomResourceDefinitionStatus
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CustomResourceDefinitionList is a list of CustomResourceDefinition objects.
type CustomResourceDefinitionList struct {
metav1.TypeMeta
metav1.ListMeta
// Items individual CustomResourceDefinitions
Items []CustomResourceDefinition
}
// CustomResourceValidation is a list of validation methods for CustomResources.
type CustomResourceValidation struct {
// OpenAPIV3Schema is the OpenAPI v3 schema to be validated against.
OpenAPIV3Schema *JSONSchemaProps
}
// CustomResourceSubresources defines the status and scale subresources for CustomResources.
type CustomResourceSubresources struct {
// Status denotes the status subresource for CustomResources
Status *CustomResourceSubresourceStatus
// Scale denotes the scale subresource for CustomResources
Scale *CustomResourceSubresourceScale
}
// CustomResourceSubresourceStatus defines how to serve the status subresource for CustomResources.
// Status is represented by the `.status` JSON path inside of a CustomResource. When set,
// * exposes a /status subresource for the custom resource
// * PUT requests to the /status subresource take a custom resource object, and ignore changes to anything except the status stanza
// * PUT/POST/PATCH requests to the custom resource ignore changes to the status stanza
type CustomResourceSubresourceStatus struct{}
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.
type CustomResourceSubresourceScale struct {
// SpecReplicasPath defines the JSON path inside of a CustomResource that corresponds to Scale.Spec.Replicas.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under .spec.
// If there is no value under the given path in the CustomResource, the /scale subresource will return an error on GET.
SpecReplicasPath string
// StatusReplicasPath defines the JSON path inside of a CustomResource that corresponds to Scale.Status.Replicas.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under .status.
// If there is no value under the given path in the CustomResource, the status replica value in the /scale subresource
// will default to 0.
StatusReplicasPath string
// LabelSelectorPath defines the JSON path inside of a CustomResource that corresponds to Scale.Status.Selector.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under .status or .spec.
// Must be set to work with HPA.
// The field pointed by this JSON path must be a string field (not a complex selector struct)
// which contains a serialized label selector in string form.
// More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
// If there is no value under the given path in the CustomResource, the status label selector value in the /scale
// subresource will default to the empty string.
// +optional
LabelSelectorPath *string
}

View File

@ -0,0 +1,151 @@
/*
Copyright 2017 The Kubernetes 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 apiextensions
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
type JSONSchemaProps struct {
ID string
Schema JSONSchemaURL
Ref *string
Description string
Type string
Nullable bool
Format string
Title string
Default *JSON
Maximum *float64
ExclusiveMaximum bool
Minimum *float64
ExclusiveMinimum bool
MaxLength *int64
MinLength *int64
Pattern string
MaxItems *int64
MinItems *int64
UniqueItems bool
MultipleOf *float64
Enum []JSON
MaxProperties *int64
MinProperties *int64
Required []string
Items *JSONSchemaPropsOrArray
AllOf []JSONSchemaProps
OneOf []JSONSchemaProps
AnyOf []JSONSchemaProps
Not *JSONSchemaProps
Properties map[string]JSONSchemaProps
AdditionalProperties *JSONSchemaPropsOrBool
PatternProperties map[string]JSONSchemaProps
Dependencies JSONSchemaDependencies
AdditionalItems *JSONSchemaPropsOrBool
Definitions JSONSchemaDefinitions
ExternalDocs *ExternalDocumentation
Example *JSON
// x-kubernetes-preserve-unknown-fields stops the API server
// decoding step from pruning fields which are not specified
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
// This can either be true or undefined. False is forbidden.
XPreserveUnknownFields *bool
// x-kubernetes-embedded-resource defines that the value is an
// embedded Kubernetes runtime.Object, with TypeMeta and
// ObjectMeta. The type must be object. It is allowed to further
// restrict the embedded object. Both ObjectMeta and TypeMeta
// are validated automatically. x-kubernetes-preserve-unknown-fields
// must be true.
XEmbeddedResource bool
// x-kubernetes-int-or-string specifies that this value is
// either an integer or a string. If this is true, an empty
// type is allowed and type as child of anyOf is permitted
// if following one of the following patterns:
//
// 1) anyOf:
// - type: integer
// - type: string
// 2) allOf:
// - anyOf:
// - type: integer
// - type: string
// - ... zero or more
XIntOrString bool
// x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type `map` by specifying the keys used
// as the index of the map.
//
// This tag MUST only be used on lists that have the "x-kubernetes-list-type"
// extension set to "map". Also, the values specified for this attribute must
// be a scalar typed field of the child structure (no nesting is supported).
XListMapKeys []string
// x-kubernetes-list-type annotates an array to further describe its topology.
// This extension must only be used on lists and may have 3 possible values:
//
// 1) `atomic`: the list is treated as a single entity, like a scalar.
// Atomic lists will be entirely replaced when updated. This extension
// may be used on any type of list (struct, scalar, ...).
// 2) `set`:
// Sets are lists that must not have multiple items with the same value. Each
// value must be a scalar (or another atomic type).
// 3) `map`:
// These lists are like maps in that their elements have a non-index key
// used to identify them. Order is preserved upon merge. The map tag
// must only be used on a list with elements of type object.
XListType *string
}
// JSON represents any valid JSON value.
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
type JSON interface{}
// JSONSchemaURL represents a schema url.
type JSONSchemaURL string
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
type JSONSchemaPropsOrArray struct {
Schema *JSONSchemaProps
JSONSchemas []JSONSchemaProps
}
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
// Defaults to true for the boolean property.
type JSONSchemaPropsOrBool struct {
Allows bool
Schema *JSONSchemaProps
}
// JSONSchemaDependencies represent a dependencies property.
type JSONSchemaDependencies map[string]JSONSchemaPropsOrStringArray
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
type JSONSchemaPropsOrStringArray struct {
Schema *JSONSchemaProps
Property []string
}
// JSONSchemaDefinitions contains the models explicitly defined in this spec.
type JSONSchemaDefinitions map[string]JSONSchemaProps
// ExternalDocumentation allows referencing an external resource for extended documentation.
type ExternalDocumentation struct {
Description string
URL string
}

View File

@ -0,0 +1,212 @@
/*
Copyright 2019 The Kubernetes 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 v1
import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/json"
)
func addConversionFuncs(scheme *runtime.Scheme) error {
// Add non-generated conversion functions
err := scheme.AddConversionFuncs(
Convert_apiextensions_JSONSchemaProps_To_v1_JSONSchemaProps,
Convert_apiextensions_JSON_To_v1_JSON,
Convert_v1_JSON_To_apiextensions_JSON,
)
if err != nil {
return err
}
return nil
}
func Convert_apiextensions_JSONSchemaProps_To_v1_JSONSchemaProps(in *apiextensions.JSONSchemaProps, out *JSONSchemaProps, s conversion.Scope) error {
if err := autoConvert_apiextensions_JSONSchemaProps_To_v1_JSONSchemaProps(in, out, s); err != nil {
return err
}
if in.Default != nil && *(in.Default) == nil {
out.Default = nil
}
if in.Example != nil && *(in.Example) == nil {
out.Example = nil
}
return nil
}
func Convert_apiextensions_JSON_To_v1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
raw, err := json.Marshal(*in)
if err != nil {
return err
}
out.Raw = raw
return nil
}
func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
if in != nil {
var i interface{}
if err := json.Unmarshal(in.Raw, &i); err != nil {
return err
}
*out = i
} else {
out = nil
}
return nil
}
func Convert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefinitionSpec(in *apiextensions.CustomResourceDefinitionSpec, out *CustomResourceDefinitionSpec, s conversion.Scope) error {
if err := autoConvert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefinitionSpec(in, out, s); err != nil {
return err
}
if len(out.Versions) == 0 && len(in.Version) > 0 {
// no versions were specified, and a version name was specified
out.Versions = []CustomResourceDefinitionVersion{{Name: in.Version, Served: true, Storage: true}}
}
// If spec.{subresources,validation,additionalPrinterColumns} exists, move to versions
if in.Subresources != nil {
subresources := &CustomResourceSubresources{}
if err := Convert_apiextensions_CustomResourceSubresources_To_v1_CustomResourceSubresources(in.Subresources, subresources, s); err != nil {
return err
}
for i := range out.Versions {
out.Versions[i].Subresources = subresources
}
}
if in.Validation != nil {
schema := &CustomResourceValidation{}
if err := Convert_apiextensions_CustomResourceValidation_To_v1_CustomResourceValidation(in.Validation, schema, s); err != nil {
return err
}
for i := range out.Versions {
out.Versions[i].Schema = schema
}
}
if in.AdditionalPrinterColumns != nil {
additionalPrinterColumns := make([]CustomResourceColumnDefinition, len(in.AdditionalPrinterColumns))
for i := range in.AdditionalPrinterColumns {
if err := Convert_apiextensions_CustomResourceColumnDefinition_To_v1_CustomResourceColumnDefinition(&in.AdditionalPrinterColumns[i], &additionalPrinterColumns[i], s); err != nil {
return err
}
}
for i := range out.Versions {
out.Versions[i].AdditionalPrinterColumns = additionalPrinterColumns
}
}
return nil
}
func Convert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in *CustomResourceDefinitionSpec, out *apiextensions.CustomResourceDefinitionSpec, s conversion.Scope) error {
if err := autoConvert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in, out, s); err != nil {
return nil
}
if len(out.Versions) == 0 {
return nil
}
// Copy versions[0] to version
out.Version = out.Versions[0].Name
// If versions[*].{subresources,schema,additionalPrinterColumns} are identical, move to spec
subresources := out.Versions[0].Subresources
subresourcesIdentical := true
validation := out.Versions[0].Schema
validationIdentical := true
additionalPrinterColumns := out.Versions[0].AdditionalPrinterColumns
additionalPrinterColumnsIdentical := true
// Detect if per-version fields are identical
for _, v := range out.Versions {
if subresourcesIdentical && !apiequality.Semantic.DeepEqual(v.Subresources, subresources) {
subresourcesIdentical = false
}
if validationIdentical && !apiequality.Semantic.DeepEqual(v.Schema, validation) {
validationIdentical = false
}
if additionalPrinterColumnsIdentical && !apiequality.Semantic.DeepEqual(v.AdditionalPrinterColumns, additionalPrinterColumns) {
additionalPrinterColumnsIdentical = false
}
}
// If they are, set the top-level fields and clear the per-version fields
if subresourcesIdentical {
out.Subresources = subresources
}
if validationIdentical {
out.Validation = validation
}
if additionalPrinterColumnsIdentical {
out.AdditionalPrinterColumns = additionalPrinterColumns
}
for i := range out.Versions {
if subresourcesIdentical {
out.Versions[i].Subresources = nil
}
if validationIdentical {
out.Versions[i].Schema = nil
}
if additionalPrinterColumnsIdentical {
out.Versions[i].AdditionalPrinterColumns = nil
}
}
return nil
}
func Convert_v1_CustomResourceConversion_To_apiextensions_CustomResourceConversion(in *CustomResourceConversion, out *apiextensions.CustomResourceConversion, s conversion.Scope) error {
if err := autoConvert_v1_CustomResourceConversion_To_apiextensions_CustomResourceConversion(in, out, s); err != nil {
return err
}
out.WebhookClientConfig = nil
out.ConversionReviewVersions = nil
if in.Webhook != nil {
out.ConversionReviewVersions = in.Webhook.ConversionReviewVersions
if in.Webhook.ClientConfig != nil {
out.WebhookClientConfig = &apiextensions.WebhookClientConfig{}
if err := Convert_v1_WebhookClientConfig_To_apiextensions_WebhookClientConfig(in.Webhook.ClientConfig, out.WebhookClientConfig, s); err != nil {
return err
}
}
}
return nil
}
func Convert_apiextensions_CustomResourceConversion_To_v1_CustomResourceConversion(in *apiextensions.CustomResourceConversion, out *CustomResourceConversion, s conversion.Scope) error {
if err := autoConvert_apiextensions_CustomResourceConversion_To_v1_CustomResourceConversion(in, out, s); err != nil {
return err
}
out.Webhook = nil
if in.WebhookClientConfig != nil || in.ConversionReviewVersions != nil {
out.Webhook = &WebhookConversion{}
out.Webhook.ConversionReviewVersions = in.ConversionReviewVersions
if in.WebhookClientConfig != nil {
out.Webhook.ClientConfig = &WebhookClientConfig{}
if err := Convert_apiextensions_WebhookClientConfig_To_v1_WebhookClientConfig(in.WebhookClientConfig, out.Webhook.ClientConfig, s); err != nil {
return err
}
}
}
return nil
}

View File

@ -0,0 +1,248 @@
/*
Copyright 2019 The Kubernetes 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 v1
// TODO: Update this after a tag is created for interface fields in DeepCopy
func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
if in == nil {
return nil
}
out := new(JSONSchemaProps)
*out = *in
if in.Ref != nil {
in, out := &in.Ref, &out.Ref
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
}
if in.Maximum != nil {
in, out := &in.Maximum, &out.Maximum
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.Minimum != nil {
in, out := &in.Minimum, &out.Minimum
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.MaxLength != nil {
in, out := &in.MaxLength, &out.MaxLength
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinLength != nil {
in, out := &in.MinLength, &out.MinLength
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MaxItems != nil {
in, out := &in.MaxItems, &out.MaxItems
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinItems != nil {
in, out := &in.MinItems, &out.MinItems
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MultipleOf != nil {
in, out := &in.MultipleOf, &out.MultipleOf
if *in == nil {
*out = nil
} else {
*out = new(float64)
**out = **in
}
}
if in.MaxProperties != nil {
in, out := &in.MaxProperties, &out.MaxProperties
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.MinProperties != nil {
in, out := &in.MinProperties, &out.MinProperties
if *in == nil {
*out = nil
} else {
*out = new(int64)
**out = **in
}
}
if in.Required != nil {
in, out := &in.Required, &out.Required
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Items != nil {
in, out := &in.Items, &out.Items
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrArray)
(*in).DeepCopyInto(*out)
}
}
if in.AllOf != nil {
in, out := &in.AllOf, &out.AllOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.OneOf != nil {
in, out := &in.OneOf, &out.OneOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AnyOf != nil {
in, out := &in.AnyOf, &out.AnyOf
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Not != nil {
in, out := &in.Not, &out.Not
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaProps)
(*in).DeepCopyInto(*out)
}
}
if in.Properties != nil {
in, out := &in.Properties, &out.Properties
*out = make(map[string]JSONSchemaProps, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.AdditionalProperties != nil {
in, out := &in.AdditionalProperties, &out.AdditionalProperties
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrBool)
(*in).DeepCopyInto(*out)
}
}
if in.PatternProperties != nil {
in, out := &in.PatternProperties, &out.PatternProperties
*out = make(map[string]JSONSchemaProps, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.Dependencies != nil {
in, out := &in.Dependencies, &out.Dependencies
*out = make(JSONSchemaDependencies, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.AdditionalItems != nil {
in, out := &in.AdditionalItems, &out.AdditionalItems
if *in == nil {
*out = nil
} else {
*out = new(JSONSchemaPropsOrBool)
(*in).DeepCopyInto(*out)
}
}
if in.Definitions != nil {
in, out := &in.Definitions, &out.Definitions
*out = make(JSONSchemaDefinitions, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
}
if in.ExternalDocs != nil {
in, out := &in.ExternalDocs, &out.ExternalDocs
if *in == nil {
*out = nil
} else {
*out = new(ExternalDocumentation)
(*in).DeepCopyInto(*out)
}
}
if in.XPreserveUnknownFields != nil {
in, out := &in.XPreserveUnknownFields, &out.XPreserveUnknownFields
if *in == nil {
*out = nil
} else {
*out = new(bool)
**out = **in
}
}
return out
}

View File

@ -0,0 +1,61 @@
/*
Copyright 2019 The Kubernetes 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 v1
import (
"strings"
"k8s.io/apimachinery/pkg/runtime"
utilpointer "k8s.io/utils/pointer"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return RegisterDefaults(scheme)
}
func SetDefaults_CustomResourceDefinition(obj *CustomResourceDefinition) {
SetDefaults_CustomResourceDefinitionSpec(&obj.Spec)
if len(obj.Status.StoredVersions) == 0 {
for _, v := range obj.Spec.Versions {
if v.Storage {
obj.Status.StoredVersions = append(obj.Status.StoredVersions, v.Name)
break
}
}
}
}
func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec) {
if len(obj.Names.Singular) == 0 {
obj.Names.Singular = strings.ToLower(obj.Names.Kind)
}
if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
obj.Names.ListKind = obj.Names.Kind + "List"
}
if obj.Conversion == nil {
obj.Conversion = &CustomResourceConversion{
Strategy: NoneConverter,
}
}
}
// SetDefaults_ServiceReference sets defaults for Webhook's ServiceReference
func SetDefaults_ServiceReference(obj *ServiceReference) {
if obj.Port == nil {
obj.Port = utilpointer.Int32Ptr(443)
}
}

View File

@ -0,0 +1,25 @@
/*
Copyright 2019 The Kubernetes 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.
*/
// +k8s:deepcopy-gen=package
// +k8s:protobuf-gen=package
// +k8s:conversion-gen=k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
// +k8s:defaulter-gen=TypeMeta
// +k8s:openapi-gen=true
// +groupName=apiextensions.k8s.io
// Package v1 is the v1 version of the API.
package v1 // import "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,592 @@
/*
Copyright The Kubernetes 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.
*/
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
syntax = 'proto2';
package k8s.io.apiextensions_apiserver.pkg.apis.apiextensions.v1;
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
// Package-wide variables from generator "generated".
option go_package = "v1";
// ConversionRequest describes the conversion request parameters.
message ConversionRequest {
// uid is an identifier for the individual request/response. It allows distinguishing instances of requests which are
// otherwise identical (parallel requests, etc).
// The UID is meant to track the round trip (request/response) between the Kubernetes API server and the webhook, not the user request.
// It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
optional string uid = 1;
// desiredAPIVersion is the version to convert given objects to. e.g. "myapi.example.com/v1"
optional string desiredAPIVersion = 2;
// objects is the list of custom resource objects to be converted.
repeated k8s.io.apimachinery.pkg.runtime.RawExtension objects = 3;
}
// ConversionResponse describes a conversion response.
message ConversionResponse {
// uid is an identifier for the individual request/response.
// This should be copied over from the corresponding `request.uid`.
optional string uid = 1;
// convertedObjects is the list of converted version of `request.objects` if the `result` is successful, otherwise empty.
// The webhook is expected to set `apiVersion` of these objects to the `request.desiredAPIVersion`. The list
// must also have the same size as the input list with the same objects in the same order (equal kind, metadata.uid, metadata.name and metadata.namespace).
// The webhook is allowed to mutate labels and annotations. Any other change to the metadata is silently ignored.
repeated k8s.io.apimachinery.pkg.runtime.RawExtension convertedObjects = 2;
// result contains the result of conversion with extra details if the conversion failed. `result.status` determines if
// the conversion failed or succeeded. The `result.status` field is required and represents the success or failure of the
// conversion. A successful conversion must set `result.status` to `Success`. A failed conversion must set
// `result.status` to `Failure` and provide more details in `result.message` and return http status 200. The `result.message`
// will be used to construct an error message for the end user.
optional k8s.io.apimachinery.pkg.apis.meta.v1.Status result = 3;
}
// ConversionReview describes a conversion request/response.
message ConversionReview {
// request describes the attributes for the conversion request.
// +optional
optional ConversionRequest request = 1;
// response describes the attributes for the conversion response.
// +optional
optional ConversionResponse response = 2;
}
// CustomResourceColumnDefinition specifies a column for server side printing.
message CustomResourceColumnDefinition {
// name is a human readable name for the column.
optional string name = 1;
// type is an OpenAPI type definition for this column.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
optional string type = 2;
// format is an optional OpenAPI type definition for this column. The 'name' format is applied
// to the primary identifier column to assist in clients identifying column is the resource name.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
// +optional
optional string format = 3;
// description is a human readable description of this column.
// +optional
optional string description = 4;
// priority is an integer defining the relative importance of this column compared to others. Lower
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
// should be given a priority greater than 0.
// +optional
optional int32 priority = 5;
// jsonPath is a simple JSON path (i.e. with array notation) which is evaluated against
// each custom resource to produce the value for this column.
optional string jsonPath = 6;
}
// CustomResourceConversion describes how to convert different versions of a CR.
message CustomResourceConversion {
// strategy specifies how custom resources are converted between versions. Allowed values are:
// - `None`: The converter only change the apiVersion and would not touch any other field in the custom resource.
// - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information
// is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhook to be set.
optional string strategy = 1;
// webhook describes how to call the conversion webhook. Required when `strategy` is set to `Webhook`.
// +optional
optional WebhookConversion webhook = 2;
}
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format
// <.spec.name>.<.spec.group>.
message CustomResourceDefinition {
optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1;
// spec describes how the user wants the resources to appear
optional CustomResourceDefinitionSpec spec = 2;
// status indicates the actual state of the CustomResourceDefinition
// +optional
optional CustomResourceDefinitionStatus status = 3;
}
// CustomResourceDefinitionCondition contains details for the current condition of this pod.
message CustomResourceDefinitionCondition {
// type is the type of the condition. Types include Established, NamesAccepted and Terminating.
optional string type = 1;
// status is the status of the condition.
// Can be True, False, Unknown.
optional string status = 2;
// lastTransitionTime last time the condition transitioned from one status to another.
// +optional
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time lastTransitionTime = 3;
// reason is a unique, one-word, CamelCase reason for the condition's last transition.
// +optional
optional string reason = 4;
// message is a human-readable message indicating details about last transition.
// +optional
optional string message = 5;
}
// CustomResourceDefinitionList is a list of CustomResourceDefinition objects.
message CustomResourceDefinitionList {
optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1;
// items list individual CustomResourceDefinition objects
repeated CustomResourceDefinition items = 2;
}
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
message CustomResourceDefinitionNames {
// plural is the plural name of the resource to serve.
// The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
// Must be all lowercase.
optional string plural = 1;
// singular is the singular name of the resource. It must be all lowercase. Defaults to lowercased `kind`.
// +optional
optional string singular = 2;
// shortNames are short names for the resource, exposed in API discovery documents,
// and used by clients to support invocations like `kubectl get <shortname>`.
// It must be all lowercase.
// +optional
repeated string shortNames = 3;
// kind is the serialized kind of the resource. It is normally CamelCase and singular.
// Custom resource instances will use this value as the `kind` attribute in API calls.
optional string kind = 4;
// listKind is the serialized kind of the list for this resource. Defaults to "`kind`List".
// +optional
optional string listKind = 5;
// categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
// This is published in API discovery documents, and used by clients to support invocations like
// `kubectl get all`.
// +optional
repeated string categories = 6;
}
// CustomResourceDefinitionSpec describes how a user wants their resource to appear
message CustomResourceDefinitionSpec {
// group is the API group of the defined custom resource.
// The custom resources are served under `/apis/<group>/...`.
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
optional string group = 1;
// names specify the resource and kind names for the custom resource.
optional CustomResourceDefinitionNames names = 3;
// scope indicates whether the defined custom resource is cluster- or namespace-scoped.
// Allowed values are `Cluster` and `Namespaced`. Default is `Namespaced`.
optional string scope = 4;
// versions is the list of all API versions of the defined custom resource.
// Version names are used to compute the order in which served versions are listed in API discovery.
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
// then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
// major version, then minor version. An example sorted list of versions:
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
repeated CustomResourceDefinitionVersion versions = 7;
// conversion defines conversion settings for the CRD.
// +optional
optional CustomResourceConversion conversion = 9;
// preserveUnknownFields indicates that object fields which are not specified
// in the OpenAPI schema should be preserved when persisting to storage.
// apiVersion, kind, metadata and known fields inside metadata are always preserved.
// This field is deprecated in favor of setting `x-preserve-unknown-fields` to true in `spec.versions[*].schema.openAPIV3Schema`.
// See https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#pruning-versus-preserving-unknown-fields for details.
// +optional
optional bool preserveUnknownFields = 10;
}
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
message CustomResourceDefinitionStatus {
// conditions indicate state for particular aspects of a CustomResourceDefinition
// +optional
repeated CustomResourceDefinitionCondition conditions = 1;
// acceptedNames are the names that are actually being used to serve discovery.
// They may be different than the names in spec.
optional CustomResourceDefinitionNames acceptedNames = 2;
// storedVersions lists all versions of CustomResources that were ever persisted. Tracking these
// versions allows a migration path for stored versions in etcd. The field is mutable
// so a migration controller can finish a migration to another version (ensuring
// no old objects are left in storage), and then remove the rest of the
// versions from this list.
// Versions may not be removed from `spec.versions` while they exist in this list.
repeated string storedVersions = 3;
}
// CustomResourceDefinitionVersion describes a version for CRD.
message CustomResourceDefinitionVersion {
// name is the version name, e.g. v1, v2beta1, etc.
// The custom resources are served under this version at `/apis/<group>/<version>/...` if `served` is true.
optional string name = 1;
// served is a flag enabling/disabling this version from being served via REST APIs
optional bool served = 2;
// storage indicates this version should be used when persisting custom resources to storage.
// There must be exactly one version with storage=true.
optional bool storage = 3;
// schema describes the schema used for validation, pruning, and defaulting of this version of the custom resource.
// +optional
optional CustomResourceValidation schema = 4;
// subresources specify what subresources this version of the defined custom resource have.
// +optional
optional CustomResourceSubresources subresources = 5;
// additionalPrinterColumns specifies additional columns returned in Table output.
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
// If no columns are specified, a single column displaying the age of the custom resource is used.
// +optional
repeated CustomResourceColumnDefinition additionalPrinterColumns = 6;
}
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.
message CustomResourceSubresourceScale {
// specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `spec.replicas`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.spec`.
// If there is no value under the given path in the custom resource, the `/scale` subresource will return an error on GET.
optional string specReplicasPath = 1;
// statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `status.replicas`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.status`.
// If there is no value under the given path in the custom resource, the `status.replicas` value in the `/scale` subresource
// will default to 0.
optional string statusReplicasPath = 2;
// labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale `status.selector`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.status` or `.spec`.
// Must be set to work with HorizontalPodAutoscaler.
// The field pointed by this JSON path must be a string field (not a complex selector struct)
// which contains a serialized label selector in string form.
// More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
// If there is no value under the given path in the custom resource, the `status.selector` value in the `/scale`
// subresource will default to the empty string.
// +optional
optional string labelSelectorPath = 3;
}
// CustomResourceSubresourceStatus defines how to serve the status subresource for CustomResources.
// Status is represented by the `.status` JSON path inside of a CustomResource. When set,
// * exposes a /status subresource for the custom resource
// * PUT requests to the /status subresource take a custom resource object, and ignore changes to anything except the status stanza
// * PUT/POST/PATCH requests to the custom resource ignore changes to the status stanza
message CustomResourceSubresourceStatus {
}
// CustomResourceSubresources defines the status and scale subresources for CustomResources.
message CustomResourceSubresources {
// status indicates the custom resource should serve a `/status` subresource.
// When enabled:
// 1. requests to the custom resource primary endpoint ignore changes to the `status` stanza of the object.
// 2. requests to the custom resource `/status` subresource ignore changes to anything other than the `status` stanza of the object.
// +optional
optional CustomResourceSubresourceStatus status = 1;
// scale indicates the custom resource should serve a `/scale` subresource that returns an `autoscaling/v1` Scale object.
// +optional
optional CustomResourceSubresourceScale scale = 2;
}
// CustomResourceValidation is a list of validation methods for CustomResources.
message CustomResourceValidation {
// openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning.
// +optional
optional JSONSchemaProps openAPIV3Schema = 1;
}
// ExternalDocumentation allows referencing an external resource for extended documentation.
message ExternalDocumentation {
optional string description = 1;
optional string url = 2;
}
// JSON represents any valid JSON value.
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
message JSON {
optional bytes raw = 1;
}
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
message JSONSchemaProps {
optional string id = 1;
optional string schema = 2;
optional string ref = 3;
optional string description = 4;
optional string type = 5;
optional string format = 6;
optional string title = 7;
// default is a default value for undefined object fields.
// Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
// Defaulting requires spec.preserveUnknownFields to be false.
optional JSON default = 8;
optional double maximum = 9;
optional bool exclusiveMaximum = 10;
optional double minimum = 11;
optional bool exclusiveMinimum = 12;
optional int64 maxLength = 13;
optional int64 minLength = 14;
optional string pattern = 15;
optional int64 maxItems = 16;
optional int64 minItems = 17;
optional bool uniqueItems = 18;
optional double multipleOf = 19;
repeated JSON enum = 20;
optional int64 maxProperties = 21;
optional int64 minProperties = 22;
repeated string required = 23;
optional JSONSchemaPropsOrArray items = 24;
repeated JSONSchemaProps allOf = 25;
repeated JSONSchemaProps oneOf = 26;
repeated JSONSchemaProps anyOf = 27;
optional JSONSchemaProps not = 28;
map<string, JSONSchemaProps> properties = 29;
optional JSONSchemaPropsOrBool additionalProperties = 30;
map<string, JSONSchemaProps> patternProperties = 31;
map<string, JSONSchemaPropsOrStringArray> dependencies = 32;
optional JSONSchemaPropsOrBool additionalItems = 33;
map<string, JSONSchemaProps> definitions = 34;
optional ExternalDocumentation externalDocs = 35;
optional JSON example = 36;
optional bool nullable = 37;
// x-kubernetes-preserve-unknown-fields stops the API server
// decoding step from pruning fields which are not specified
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
// This can either be true or undefined. False is forbidden.
optional bool xKubernetesPreserveUnknownFields = 38;
// x-kubernetes-embedded-resource defines that the value is an
// embedded Kubernetes runtime.Object, with TypeMeta and
// ObjectMeta. The type must be object. It is allowed to further
// restrict the embedded object. kind, apiVersion and metadata
// are validated automatically. x-kubernetes-preserve-unknown-fields
// is allowed to be true, but does not have to be if the object
// is fully specified (up to kind, apiVersion, metadata).
optional bool xKubernetesEmbeddedResource = 39;
// x-kubernetes-int-or-string specifies that this value is
// either an integer or a string. If this is true, an empty
// type is allowed and type as child of anyOf is permitted
// if following one of the following patterns:
//
// 1) anyOf:
// - type: integer
// - type: string
// 2) allOf:
// - anyOf:
// - type: integer
// - type: string
// - ... zero or more
optional bool xKubernetesIntOrString = 40;
// x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type `map` by specifying the keys used
// as the index of the map.
//
// This tag MUST only be used on lists that have the "x-kubernetes-list-type"
// extension set to "map". Also, the values specified for this attribute must
// be a scalar typed field of the child structure (no nesting is supported).
//
// +optional
repeated string xKubernetesListMapKeys = 41;
// x-kubernetes-list-type annotates an array to further describe its topology.
// This extension must only be used on lists and may have 3 possible values:
//
// 1) `atomic`: the list is treated as a single entity, like a scalar.
// Atomic lists will be entirely replaced when updated. This extension
// may be used on any type of list (struct, scalar, ...).
// 2) `set`:
// Sets are lists that must not have multiple items with the same value. Each
// value must be a scalar (or another atomic type).
// 3) `map`:
// These lists are like maps in that their elements have a non-index key
// used to identify them. Order is preserved upon merge. The map tag
// must only be used on a list with elements of type object.
// Defaults to atomic for arrays.
// +optional
optional string xKubernetesListType = 42;
}
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
message JSONSchemaPropsOrArray {
optional JSONSchemaProps schema = 1;
repeated JSONSchemaProps jSONSchemas = 2;
}
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
// Defaults to true for the boolean property.
message JSONSchemaPropsOrBool {
optional bool allows = 1;
optional JSONSchemaProps schema = 2;
}
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
message JSONSchemaPropsOrStringArray {
optional JSONSchemaProps schema = 1;
repeated string property = 2;
}
// ServiceReference holds a reference to Service.legacy.k8s.io
message ServiceReference {
// namespace is the namespace of the service.
// Required
optional string namespace = 1;
// name is the name of the service.
// Required
optional string name = 2;
// path is an optional URL path at which the webhook will be contacted.
// +optional
optional string path = 3;
// port is an optional service port at which the webhook will be contacted.
// `port` should be a valid port number (1-65535, inclusive).
// Defaults to 443 for backward compatibility.
// +optional
optional int32 port = 4;
}
// WebhookClientConfig contains the information to make a TLS connection with the webhook.
message WebhookClientConfig {
// url gives the location of the webhook, in standard URL form
// (`scheme://host:port/path`). Exactly one of `url` or `service`
// must be specified.
//
// The `host` should not refer to a service running in the cluster; use
// the `service` field instead. The host might be resolved via external
// DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
// in-cluster DNS as that would be a layering violation). `host` may
// also be an IP address.
//
// Please note that using `localhost` or `127.0.0.1` as a `host` is
// risky unless you take great care to run this webhook on all hosts
// which run an apiserver which might need to make calls to this
// webhook. Such installs are likely to be non-portable, i.e., not easy
// to turn up in a new cluster.
//
// The scheme must be "https"; the URL must begin with "https://".
//
// A path is optional, and if present may be any string permissible in
// a URL. You may use the path to pass an arbitrary string to the
// webhook, for example, a cluster identifier.
//
// Attempting to use a user or basic auth e.g. "user:password@" is not
// allowed. Fragments ("#...") and query parameters ("?...") are not
// allowed, either.
//
// +optional
optional string url = 3;
// service is a reference to the service for this webhook. Either
// service or url must be specified.
//
// If the webhook is running within the cluster, then you should use `service`.
//
// +optional
optional ServiceReference service = 1;
// caBundle is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
// If unspecified, system trust roots on the apiserver are used.
// +optional
optional bytes caBundle = 2;
}
// WebhookConversion describes how to call a conversion webhook
message WebhookConversion {
// clientConfig is the instructions for how to call the webhook if strategy is `Webhook`.
// +optional
optional WebhookClientConfig clientConfig = 2;
// conversionReviewVersions is an ordered list of preferred `ConversionReview`
// versions the Webhook expects. The API server will use the first version in
// the list which it supports. If none of the versions specified in this list
// are supported by API server, conversion will fail for the custom resource.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
repeated string conversionReviewVersions = 3;
}

View File

@ -0,0 +1,135 @@
/*
Copyright 2019 The Kubernetes 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 v1
import (
"errors"
"k8s.io/apimachinery/pkg/util/json"
)
var jsTrue = []byte("true")
var jsFalse = []byte("false")
func (s JSONSchemaPropsOrBool) MarshalJSON() ([]byte, error) {
if s.Schema != nil {
return json.Marshal(s.Schema)
}
if s.Schema == nil && !s.Allows {
return jsFalse, nil
}
return jsTrue, nil
}
func (s *JSONSchemaPropsOrBool) UnmarshalJSON(data []byte) error {
var nw JSONSchemaPropsOrBool
switch {
case len(data) == 0:
case data[0] == '{':
var sch JSONSchemaProps
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Allows = true
nw.Schema = &sch
case len(data) == 4 && string(data) == "true":
nw.Allows = true
case len(data) == 5 && string(data) == "false":
nw.Allows = false
default:
return errors.New("boolean or JSON schema expected")
}
*s = nw
return nil
}
func (s JSONSchemaPropsOrStringArray) MarshalJSON() ([]byte, error) {
if len(s.Property) > 0 {
return json.Marshal(s.Property)
}
if s.Schema != nil {
return json.Marshal(s.Schema)
}
return []byte("null"), nil
}
func (s *JSONSchemaPropsOrStringArray) UnmarshalJSON(data []byte) error {
var first byte
if len(data) > 1 {
first = data[0]
}
var nw JSONSchemaPropsOrStringArray
if first == '{' {
var sch JSONSchemaProps
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Schema = &sch
}
if first == '[' {
if err := json.Unmarshal(data, &nw.Property); err != nil {
return err
}
}
*s = nw
return nil
}
func (s JSONSchemaPropsOrArray) MarshalJSON() ([]byte, error) {
if len(s.JSONSchemas) > 0 {
return json.Marshal(s.JSONSchemas)
}
return json.Marshal(s.Schema)
}
func (s *JSONSchemaPropsOrArray) UnmarshalJSON(data []byte) error {
var nw JSONSchemaPropsOrArray
var first byte
if len(data) > 1 {
first = data[0]
}
if first == '{' {
var sch JSONSchemaProps
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Schema = &sch
}
if first == '[' {
if err := json.Unmarshal(data, &nw.JSONSchemas); err != nil {
return err
}
}
*s = nw
return nil
}
func (s JSON) MarshalJSON() ([]byte, error) {
if len(s.Raw) > 0 {
return s.Raw, nil
}
return []byte("null"), nil
}
func (s *JSON) UnmarshalJSON(data []byte) error {
if len(data) > 0 && string(data) != "null" {
s.Raw = data
}
return nil
}

View File

@ -0,0 +1,62 @@
/*
Copyright 2019 The Kubernetes 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 v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
const GroupName = "apiextensions.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// Resource takes an unqualified resource and returns back a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CustomResourceDefinition{},
&CustomResourceDefinitionList{},
&ConversionReview{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(addDefaultingFuncs, addConversionFuncs)
}

View File

@ -0,0 +1,463 @@
/*
Copyright 2019 The Kubernetes 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 v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
)
// ConversionStrategyType describes different conversion types.
type ConversionStrategyType string
const (
// KubeAPIApprovedAnnotation is an annotation that must be set to create a CRD for the k8s.io, *.k8s.io, kubernetes.io, or *.kubernetes.io namespaces.
// The value should be a link to a URL where the current spec was approved, so updates to the spec should also update the URL.
// If the API is unapproved, you may set the annotation to a string starting with `"unapproved"`. For instance, `"unapproved, temporarily squatting"` or `"unapproved, experimental-only"`. This is discouraged.
KubeAPIApprovedAnnotation = "api-approved.kubernetes.io"
// NoneConverter is a converter that only sets apiversion of the CR and leave everything else unchanged.
NoneConverter ConversionStrategyType = "None"
// WebhookConverter is a converter that calls to an external webhook to convert the CR.
WebhookConverter ConversionStrategyType = "Webhook"
)
// CustomResourceDefinitionSpec describes how a user wants their resource to appear
type CustomResourceDefinitionSpec struct {
// group is the API group of the defined custom resource.
// The custom resources are served under `/apis/<group>/...`.
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
// names specify the resource and kind names for the custom resource.
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
// scope indicates whether the defined custom resource is cluster- or namespace-scoped.
// Allowed values are `Cluster` and `Namespaced`. Default is `Namespaced`.
Scope ResourceScope `json:"scope" protobuf:"bytes,4,opt,name=scope,casttype=ResourceScope"`
// versions is the list of all API versions of the defined custom resource.
// Version names are used to compute the order in which served versions are listed in API discovery.
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
// then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
// major version, then minor version. An example sorted list of versions:
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
Versions []CustomResourceDefinitionVersion `json:"versions" protobuf:"bytes,7,rep,name=versions"`
// conversion defines conversion settings for the CRD.
// +optional
Conversion *CustomResourceConversion `json:"conversion,omitempty" protobuf:"bytes,9,opt,name=conversion"`
// preserveUnknownFields indicates that object fields which are not specified
// in the OpenAPI schema should be preserved when persisting to storage.
// apiVersion, kind, metadata and known fields inside metadata are always preserved.
// This field is deprecated in favor of setting `x-preserve-unknown-fields` to true in `spec.versions[*].schema.openAPIV3Schema`.
// See https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#pruning-versus-preserving-unknown-fields for details.
// +optional
PreserveUnknownFields bool `json:"preserveUnknownFields,omitempty" protobuf:"varint,10,opt,name=preserveUnknownFields"`
}
// CustomResourceConversion describes how to convert different versions of a CR.
type CustomResourceConversion struct {
// strategy specifies how custom resources are converted between versions. Allowed values are:
// - `None`: The converter only change the apiVersion and would not touch any other field in the custom resource.
// - `Webhook`: API Server will call to an external webhook to do the conversion. Additional information
// is needed for this option. This requires spec.preserveUnknownFields to be false, and spec.conversion.webhook to be set.
Strategy ConversionStrategyType `json:"strategy" protobuf:"bytes,1,name=strategy"`
// webhook describes how to call the conversion webhook. Required when `strategy` is set to `Webhook`.
// +optional
Webhook *WebhookConversion `json:"webhook,omitempty" protobuf:"bytes,2,opt,name=webhook"`
}
// WebhookConversion describes how to call a conversion webhook
type WebhookConversion struct {
// clientConfig is the instructions for how to call the webhook if strategy is `Webhook`.
// +optional
ClientConfig *WebhookClientConfig `json:"clientConfig,omitempty" protobuf:"bytes,2,name=clientConfig"`
// conversionReviewVersions is an ordered list of preferred `ConversionReview`
// versions the Webhook expects. The API server will use the first version in
// the list which it supports. If none of the versions specified in this list
// are supported by API server, conversion will fail for the custom resource.
// If a persisted Webhook configuration specifies allowed versions and does not
// include any versions known to the API Server, calls to the webhook will fail.
ConversionReviewVersions []string `json:"conversionReviewVersions" protobuf:"bytes,3,rep,name=conversionReviewVersions"`
}
// WebhookClientConfig contains the information to make a TLS connection with the webhook.
type WebhookClientConfig struct {
// url gives the location of the webhook, in standard URL form
// (`scheme://host:port/path`). Exactly one of `url` or `service`
// must be specified.
//
// The `host` should not refer to a service running in the cluster; use
// the `service` field instead. The host might be resolved via external
// DNS in some apiservers (e.g., `kube-apiserver` cannot resolve
// in-cluster DNS as that would be a layering violation). `host` may
// also be an IP address.
//
// Please note that using `localhost` or `127.0.0.1` as a `host` is
// risky unless you take great care to run this webhook on all hosts
// which run an apiserver which might need to make calls to this
// webhook. Such installs are likely to be non-portable, i.e., not easy
// to turn up in a new cluster.
//
// The scheme must be "https"; the URL must begin with "https://".
//
// A path is optional, and if present may be any string permissible in
// a URL. You may use the path to pass an arbitrary string to the
// webhook, for example, a cluster identifier.
//
// Attempting to use a user or basic auth e.g. "user:password@" is not
// allowed. Fragments ("#...") and query parameters ("?...") are not
// allowed, either.
//
// +optional
URL *string `json:"url,omitempty" protobuf:"bytes,3,opt,name=url"`
// service is a reference to the service for this webhook. Either
// service or url must be specified.
//
// If the webhook is running within the cluster, then you should use `service`.
//
// +optional
Service *ServiceReference `json:"service,omitempty" protobuf:"bytes,1,opt,name=service"`
// caBundle is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.
// If unspecified, system trust roots on the apiserver are used.
// +optional
CABundle []byte `json:"caBundle,omitempty" protobuf:"bytes,2,opt,name=caBundle"`
}
// ServiceReference holds a reference to Service.legacy.k8s.io
type ServiceReference struct {
// namespace is the namespace of the service.
// Required
Namespace string `json:"namespace" protobuf:"bytes,1,opt,name=namespace"`
// name is the name of the service.
// Required
Name string `json:"name" protobuf:"bytes,2,opt,name=name"`
// path is an optional URL path at which the webhook will be contacted.
// +optional
Path *string `json:"path,omitempty" protobuf:"bytes,3,opt,name=path"`
// port is an optional service port at which the webhook will be contacted.
// `port` should be a valid port number (1-65535, inclusive).
// Defaults to 443 for backward compatibility.
// +optional
Port *int32 `json:"port,omitempty" protobuf:"varint,4,opt,name=port"`
}
// CustomResourceDefinitionVersion describes a version for CRD.
type CustomResourceDefinitionVersion struct {
// name is the version name, e.g. “v1”, “v2beta1”, etc.
// The custom resources are served under this version at `/apis/<group>/<version>/...` if `served` is true.
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
// served is a flag enabling/disabling this version from being served via REST APIs
Served bool `json:"served" protobuf:"varint,2,opt,name=served"`
// storage indicates this version should be used when persisting custom resources to storage.
// There must be exactly one version with storage=true.
Storage bool `json:"storage" protobuf:"varint,3,opt,name=storage"`
// schema describes the schema used for validation, pruning, and defaulting of this version of the custom resource.
// +optional
Schema *CustomResourceValidation `json:"schema,omitempty" protobuf:"bytes,4,opt,name=schema"`
// subresources specify what subresources this version of the defined custom resource have.
// +optional
Subresources *CustomResourceSubresources `json:"subresources,omitempty" protobuf:"bytes,5,opt,name=subresources"`
// additionalPrinterColumns specifies additional columns returned in Table output.
// See https://kubernetes.io/docs/reference/using-api/api-concepts/#receiving-resources-as-tables for details.
// If no columns are specified, a single column displaying the age of the custom resource is used.
// +optional
AdditionalPrinterColumns []CustomResourceColumnDefinition `json:"additionalPrinterColumns,omitempty" protobuf:"bytes,6,rep,name=additionalPrinterColumns"`
}
// CustomResourceColumnDefinition specifies a column for server side printing.
type CustomResourceColumnDefinition struct {
// name is a human readable name for the column.
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
// type is an OpenAPI type definition for this column.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
Type string `json:"type" protobuf:"bytes,2,opt,name=type"`
// format is an optional OpenAPI type definition for this column. The 'name' format is applied
// to the primary identifier column to assist in clients identifying column is the resource name.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for details.
// +optional
Format string `json:"format,omitempty" protobuf:"bytes,3,opt,name=format"`
// description is a human readable description of this column.
// +optional
Description string `json:"description,omitempty" protobuf:"bytes,4,opt,name=description"`
// priority is an integer defining the relative importance of this column compared to others. Lower
// numbers are considered higher priority. Columns that may be omitted in limited space scenarios
// should be given a priority greater than 0.
// +optional
Priority int32 `json:"priority,omitempty" protobuf:"bytes,5,opt,name=priority"`
// jsonPath is a simple JSON path (i.e. with array notation) which is evaluated against
// each custom resource to produce the value for this column.
JSONPath string `json:"jsonPath" protobuf:"bytes,6,opt,name=jsonPath"`
}
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
type CustomResourceDefinitionNames struct {
// plural is the plural name of the resource to serve.
// The custom resources are served under `/apis/<group>/<version>/.../<plural>`.
// Must match the name of the CustomResourceDefinition (in the form `<names.plural>.<group>`).
// Must be all lowercase.
Plural string `json:"plural" protobuf:"bytes,1,opt,name=plural"`
// singular is the singular name of the resource. It must be all lowercase. Defaults to lowercased `kind`.
// +optional
Singular string `json:"singular,omitempty" protobuf:"bytes,2,opt,name=singular"`
// shortNames are short names for the resource, exposed in API discovery documents,
// and used by clients to support invocations like `kubectl get <shortname>`.
// It must be all lowercase.
// +optional
ShortNames []string `json:"shortNames,omitempty" protobuf:"bytes,3,opt,name=shortNames"`
// kind is the serialized kind of the resource. It is normally CamelCase and singular.
// Custom resource instances will use this value as the `kind` attribute in API calls.
Kind string `json:"kind" protobuf:"bytes,4,opt,name=kind"`
// listKind is the serialized kind of the list for this resource. Defaults to "`kind`List".
// +optional
ListKind string `json:"listKind,omitempty" protobuf:"bytes,5,opt,name=listKind"`
// categories is a list of grouped resources this custom resource belongs to (e.g. 'all').
// This is published in API discovery documents, and used by clients to support invocations like
// `kubectl get all`.
// +optional
Categories []string `json:"categories,omitempty" protobuf:"bytes,6,rep,name=categories"`
}
// ResourceScope is an enum defining the different scopes available to a custom resource
type ResourceScope string
const (
ClusterScoped ResourceScope = "Cluster"
NamespaceScoped ResourceScope = "Namespaced"
)
type ConditionStatus string
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
// can't decide if a resource is in the condition or not. In the future, we could add other
// intermediate conditions, e.g. ConditionDegraded.
const (
ConditionTrue ConditionStatus = "True"
ConditionFalse ConditionStatus = "False"
ConditionUnknown ConditionStatus = "Unknown"
)
// CustomResourceDefinitionConditionType is a valid value for CustomResourceDefinitionCondition.Type
type CustomResourceDefinitionConditionType string
const (
// Established means that the resource has become active. A resource is established when all names are
// accepted without a conflict for the first time. A resource stays established until deleted, even during
// a later NamesAccepted due to changed names. Note that not all names can be changed.
Established CustomResourceDefinitionConditionType = "Established"
// NamesAccepted means the names chosen for this CustomResourceDefinition do not conflict with others in
// the group and are therefore accepted.
NamesAccepted CustomResourceDefinitionConditionType = "NamesAccepted"
// NonStructuralSchema means that one or more OpenAPI schema is not structural.
//
// A schema is structural if it specifies types for all values, with the only exceptions of those with
// - x-kubernetes-int-or-string: true — for fields which can be integer or string
// - x-kubernetes-preserve-unknown-fields: true — for raw, unspecified JSON values
// and there is no type, additionalProperties, default, nullable or x-kubernetes-* vendor extenions
// specified under allOf, anyOf, oneOf or not.
//
// Non-structural schemas will not be allowed anymore in v1 API groups. Moreover, new features will not be
// available for non-structural CRDs:
// - pruning
// - defaulting
// - read-only
// - OpenAPI publishing
// - webhook conversion
NonStructuralSchema CustomResourceDefinitionConditionType = "NonStructuralSchema"
// Terminating means that the CustomResourceDefinition has been deleted and is cleaning up.
Terminating CustomResourceDefinitionConditionType = "Terminating"
// KubernetesAPIApprovalPolicyConformant indicates that an API in *.k8s.io or *.kubernetes.io is or is not approved. For CRDs
// outside those groups, this condition will not be set. For CRDs inside those groups, the condition will
// be true if .metadata.annotations["api-approved.kubernetes.io"] is set to a URL, otherwise it will be false.
// See https://github.com/kubernetes/enhancements/pull/1111 for more details.
KubernetesAPIApprovalPolicyConformant CustomResourceDefinitionConditionType = "KubernetesAPIApprovalPolicyConformant"
)
// CustomResourceDefinitionCondition contains details for the current condition of this pod.
type CustomResourceDefinitionCondition struct {
// type is the type of the condition. Types include Established, NamesAccepted and Terminating.
Type CustomResourceDefinitionConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=CustomResourceDefinitionConditionType"`
// status is the status of the condition.
// Can be True, False, Unknown.
Status ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"`
// lastTransitionTime last time the condition transitioned from one status to another.
// +optional
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,3,opt,name=lastTransitionTime"`
// reason is a unique, one-word, CamelCase reason for the condition's last transition.
// +optional
Reason string `json:"reason,omitempty" protobuf:"bytes,4,opt,name=reason"`
// message is a human-readable message indicating details about last transition.
// +optional
Message string `json:"message,omitempty" protobuf:"bytes,5,opt,name=message"`
}
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
type CustomResourceDefinitionStatus struct {
// conditions indicate state for particular aspects of a CustomResourceDefinition
// +optional
Conditions []CustomResourceDefinitionCondition `json:"conditions" protobuf:"bytes,1,opt,name=conditions"`
// acceptedNames are the names that are actually being used to serve discovery.
// They may be different than the names in spec.
AcceptedNames CustomResourceDefinitionNames `json:"acceptedNames" protobuf:"bytes,2,opt,name=acceptedNames"`
// storedVersions lists all versions of CustomResources that were ever persisted. Tracking these
// versions allows a migration path for stored versions in etcd. The field is mutable
// so a migration controller can finish a migration to another version (ensuring
// no old objects are left in storage), and then remove the rest of the
// versions from this list.
// Versions may not be removed from `spec.versions` while they exist in this list.
StoredVersions []string `json:"storedVersions" protobuf:"bytes,3,rep,name=storedVersions"`
}
// CustomResourceCleanupFinalizer is the name of the finalizer which will delete instances of
// a CustomResourceDefinition
const CustomResourceCleanupFinalizer = "customresourcecleanup.apiextensions.k8s.io"
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CustomResourceDefinition represents a resource that should be exposed on the API server. Its name MUST be in the format
// <.spec.name>.<.spec.group>.
type CustomResourceDefinition struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// spec describes how the user wants the resources to appear
Spec CustomResourceDefinitionSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
// status indicates the actual state of the CustomResourceDefinition
// +optional
Status CustomResourceDefinitionStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// CustomResourceDefinitionList is a list of CustomResourceDefinition objects.
type CustomResourceDefinitionList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// items list individual CustomResourceDefinition objects
Items []CustomResourceDefinition `json:"items" protobuf:"bytes,2,rep,name=items"`
}
// CustomResourceValidation is a list of validation methods for CustomResources.
type CustomResourceValidation struct {
// openAPIV3Schema is the OpenAPI v3 schema to use for validation and pruning.
// +optional
OpenAPIV3Schema *JSONSchemaProps `json:"openAPIV3Schema,omitempty" protobuf:"bytes,1,opt,name=openAPIV3Schema"`
}
// CustomResourceSubresources defines the status and scale subresources for CustomResources.
type CustomResourceSubresources struct {
// status indicates the custom resource should serve a `/status` subresource.
// When enabled:
// 1. requests to the custom resource primary endpoint ignore changes to the `status` stanza of the object.
// 2. requests to the custom resource `/status` subresource ignore changes to anything other than the `status` stanza of the object.
// +optional
Status *CustomResourceSubresourceStatus `json:"status,omitempty" protobuf:"bytes,1,opt,name=status"`
// scale indicates the custom resource should serve a `/scale` subresource that returns an `autoscaling/v1` Scale object.
// +optional
Scale *CustomResourceSubresourceScale `json:"scale,omitempty" protobuf:"bytes,2,opt,name=scale"`
}
// CustomResourceSubresourceStatus defines how to serve the status subresource for CustomResources.
// Status is represented by the `.status` JSON path inside of a CustomResource. When set,
// * exposes a /status subresource for the custom resource
// * PUT requests to the /status subresource take a custom resource object, and ignore changes to anything except the status stanza
// * PUT/POST/PATCH requests to the custom resource ignore changes to the status stanza
type CustomResourceSubresourceStatus struct{}
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.
type CustomResourceSubresourceScale struct {
// specReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `spec.replicas`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.spec`.
// If there is no value under the given path in the custom resource, the `/scale` subresource will return an error on GET.
SpecReplicasPath string `json:"specReplicasPath" protobuf:"bytes,1,name=specReplicasPath"`
// statusReplicasPath defines the JSON path inside of a custom resource that corresponds to Scale `status.replicas`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.status`.
// If there is no value under the given path in the custom resource, the `status.replicas` value in the `/scale` subresource
// will default to 0.
StatusReplicasPath string `json:"statusReplicasPath" protobuf:"bytes,2,opt,name=statusReplicasPath"`
// labelSelectorPath defines the JSON path inside of a custom resource that corresponds to Scale `status.selector`.
// Only JSON paths without the array notation are allowed.
// Must be a JSON Path under `.status` or `.spec`.
// Must be set to work with HorizontalPodAutoscaler.
// The field pointed by this JSON path must be a string field (not a complex selector struct)
// which contains a serialized label selector in string form.
// More info: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions#scale-subresource
// If there is no value under the given path in the custom resource, the `status.selector` value in the `/scale`
// subresource will default to the empty string.
// +optional
LabelSelectorPath *string `json:"labelSelectorPath,omitempty" protobuf:"bytes,3,opt,name=labelSelectorPath"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ConversionReview describes a conversion request/response.
type ConversionReview struct {
metav1.TypeMeta `json:",inline"`
// request describes the attributes for the conversion request.
// +optional
Request *ConversionRequest `json:"request,omitempty" protobuf:"bytes,1,opt,name=request"`
// response describes the attributes for the conversion response.
// +optional
Response *ConversionResponse `json:"response,omitempty" protobuf:"bytes,2,opt,name=response"`
}
// ConversionRequest describes the conversion request parameters.
type ConversionRequest struct {
// uid is an identifier for the individual request/response. It allows distinguishing instances of requests which are
// otherwise identical (parallel requests, etc).
// The UID is meant to track the round trip (request/response) between the Kubernetes API server and the webhook, not the user request.
// It is suitable for correlating log entries between the webhook and apiserver, for either auditing or debugging.
UID types.UID `json:"uid" protobuf:"bytes,1,name=uid"`
// desiredAPIVersion is the version to convert given objects to. e.g. "myapi.example.com/v1"
DesiredAPIVersion string `json:"desiredAPIVersion" protobuf:"bytes,2,name=desiredAPIVersion"`
// objects is the list of custom resource objects to be converted.
Objects []runtime.RawExtension `json:"objects" protobuf:"bytes,3,rep,name=objects"`
}
// ConversionResponse describes a conversion response.
type ConversionResponse struct {
// uid is an identifier for the individual request/response.
// This should be copied over from the corresponding `request.uid`.
UID types.UID `json:"uid" protobuf:"bytes,1,name=uid"`
// convertedObjects is the list of converted version of `request.objects` if the `result` is successful, otherwise empty.
// The webhook is expected to set `apiVersion` of these objects to the `request.desiredAPIVersion`. The list
// must also have the same size as the input list with the same objects in the same order (equal kind, metadata.uid, metadata.name and metadata.namespace).
// The webhook is allowed to mutate labels and annotations. Any other change to the metadata is silently ignored.
ConvertedObjects []runtime.RawExtension `json:"convertedObjects" protobuf:"bytes,2,rep,name=convertedObjects"`
// result contains the result of conversion with extra details if the conversion failed. `result.status` determines if
// the conversion failed or succeeded. The `result.status` field is required and represents the success or failure of the
// conversion. A successful conversion must set `result.status` to `Success`. A failed conversion must set
// `result.status` to `Failure` and provide more details in `result.message` and return http status 200. The `result.message`
// will be used to construct an error message for the end user.
Result metav1.Status `json:"result" protobuf:"bytes,3,name=result"`
}

View File

@ -0,0 +1,213 @@
/*
Copyright 2019 The Kubernetes 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 v1
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
type JSONSchemaProps struct {
ID string `json:"id,omitempty" protobuf:"bytes,1,opt,name=id"`
Schema JSONSchemaURL `json:"$schema,omitempty" protobuf:"bytes,2,opt,name=schema"`
Ref *string `json:"$ref,omitempty" protobuf:"bytes,3,opt,name=ref"`
Description string `json:"description,omitempty" protobuf:"bytes,4,opt,name=description"`
Type string `json:"type,omitempty" protobuf:"bytes,5,opt,name=type"`
Format string `json:"format,omitempty" protobuf:"bytes,6,opt,name=format"`
Title string `json:"title,omitempty" protobuf:"bytes,7,opt,name=title"`
// default is a default value for undefined object fields.
// Defaulting is a beta feature under the CustomResourceDefaulting feature gate.
// Defaulting requires spec.preserveUnknownFields to be false.
Default *JSON `json:"default,omitempty" protobuf:"bytes,8,opt,name=default"`
Maximum *float64 `json:"maximum,omitempty" protobuf:"bytes,9,opt,name=maximum"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" protobuf:"bytes,10,opt,name=exclusiveMaximum"`
Minimum *float64 `json:"minimum,omitempty" protobuf:"bytes,11,opt,name=minimum"`
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" protobuf:"bytes,12,opt,name=exclusiveMinimum"`
MaxLength *int64 `json:"maxLength,omitempty" protobuf:"bytes,13,opt,name=maxLength"`
MinLength *int64 `json:"minLength,omitempty" protobuf:"bytes,14,opt,name=minLength"`
Pattern string `json:"pattern,omitempty" protobuf:"bytes,15,opt,name=pattern"`
MaxItems *int64 `json:"maxItems,omitempty" protobuf:"bytes,16,opt,name=maxItems"`
MinItems *int64 `json:"minItems,omitempty" protobuf:"bytes,17,opt,name=minItems"`
UniqueItems bool `json:"uniqueItems,omitempty" protobuf:"bytes,18,opt,name=uniqueItems"`
MultipleOf *float64 `json:"multipleOf,omitempty" protobuf:"bytes,19,opt,name=multipleOf"`
Enum []JSON `json:"enum,omitempty" protobuf:"bytes,20,rep,name=enum"`
MaxProperties *int64 `json:"maxProperties,omitempty" protobuf:"bytes,21,opt,name=maxProperties"`
MinProperties *int64 `json:"minProperties,omitempty" protobuf:"bytes,22,opt,name=minProperties"`
Required []string `json:"required,omitempty" protobuf:"bytes,23,rep,name=required"`
Items *JSONSchemaPropsOrArray `json:"items,omitempty" protobuf:"bytes,24,opt,name=items"`
AllOf []JSONSchemaProps `json:"allOf,omitempty" protobuf:"bytes,25,rep,name=allOf"`
OneOf []JSONSchemaProps `json:"oneOf,omitempty" protobuf:"bytes,26,rep,name=oneOf"`
AnyOf []JSONSchemaProps `json:"anyOf,omitempty" protobuf:"bytes,27,rep,name=anyOf"`
Not *JSONSchemaProps `json:"not,omitempty" protobuf:"bytes,28,opt,name=not"`
Properties map[string]JSONSchemaProps `json:"properties,omitempty" protobuf:"bytes,29,rep,name=properties"`
AdditionalProperties *JSONSchemaPropsOrBool `json:"additionalProperties,omitempty" protobuf:"bytes,30,opt,name=additionalProperties"`
PatternProperties map[string]JSONSchemaProps `json:"patternProperties,omitempty" protobuf:"bytes,31,rep,name=patternProperties"`
Dependencies JSONSchemaDependencies `json:"dependencies,omitempty" protobuf:"bytes,32,opt,name=dependencies"`
AdditionalItems *JSONSchemaPropsOrBool `json:"additionalItems,omitempty" protobuf:"bytes,33,opt,name=additionalItems"`
Definitions JSONSchemaDefinitions `json:"definitions,omitempty" protobuf:"bytes,34,opt,name=definitions"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty" protobuf:"bytes,35,opt,name=externalDocs"`
Example *JSON `json:"example,omitempty" protobuf:"bytes,36,opt,name=example"`
Nullable bool `json:"nullable,omitempty" protobuf:"bytes,37,opt,name=nullable"`
// x-kubernetes-preserve-unknown-fields stops the API server
// decoding step from pruning fields which are not specified
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
// This can either be true or undefined. False is forbidden.
XPreserveUnknownFields *bool `json:"x-kubernetes-preserve-unknown-fields,omitempty" protobuf:"bytes,38,opt,name=xKubernetesPreserveUnknownFields"`
// x-kubernetes-embedded-resource defines that the value is an
// embedded Kubernetes runtime.Object, with TypeMeta and
// ObjectMeta. The type must be object. It is allowed to further
// restrict the embedded object. kind, apiVersion and metadata
// are validated automatically. x-kubernetes-preserve-unknown-fields
// is allowed to be true, but does not have to be if the object
// is fully specified (up to kind, apiVersion, metadata).
XEmbeddedResource bool `json:"x-kubernetes-embedded-resource,omitempty" protobuf:"bytes,39,opt,name=xKubernetesEmbeddedResource"`
// x-kubernetes-int-or-string specifies that this value is
// either an integer or a string. If this is true, an empty
// type is allowed and type as child of anyOf is permitted
// if following one of the following patterns:
//
// 1) anyOf:
// - type: integer
// - type: string
// 2) allOf:
// - anyOf:
// - type: integer
// - type: string
// - ... zero or more
XIntOrString bool `json:"x-kubernetes-int-or-string,omitempty" protobuf:"bytes,40,opt,name=xKubernetesIntOrString"`
// x-kubernetes-list-map-keys annotates an array with the x-kubernetes-list-type `map` by specifying the keys used
// as the index of the map.
//
// This tag MUST only be used on lists that have the "x-kubernetes-list-type"
// extension set to "map". Also, the values specified for this attribute must
// be a scalar typed field of the child structure (no nesting is supported).
//
// +optional
XListMapKeys []string `json:"x-kubernetes-list-map-keys,omitempty" protobuf:"bytes,41,rep,name=xKubernetesListMapKeys"`
// x-kubernetes-list-type annotates an array to further describe its topology.
// This extension must only be used on lists and may have 3 possible values:
//
// 1) `atomic`: the list is treated as a single entity, like a scalar.
// Atomic lists will be entirely replaced when updated. This extension
// may be used on any type of list (struct, scalar, ...).
// 2) `set`:
// Sets are lists that must not have multiple items with the same value. Each
// value must be a scalar (or another atomic type).
// 3) `map`:
// These lists are like maps in that their elements have a non-index key
// used to identify them. Order is preserved upon merge. The map tag
// must only be used on a list with elements of type object.
// Defaults to atomic for arrays.
// +optional
XListType *string `json:"x-kubernetes-list-type,omitempty" protobuf:"bytes,42,opt,name=xKubernetesListType"`
}
// JSON represents any valid JSON value.
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
type JSON struct {
Raw []byte `protobuf:"bytes,1,opt,name=raw"`
}
// OpenAPISchemaType is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
//
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
func (_ JSON) OpenAPISchemaType() []string {
// TODO: return actual types when anyOf is supported
return nil
}
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
func (_ JSON) OpenAPISchemaFormat() string { return "" }
// JSONSchemaURL represents a schema url.
type JSONSchemaURL string
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
type JSONSchemaPropsOrArray struct {
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
JSONSchemas []JSONSchemaProps `protobuf:"bytes,2,rep,name=jSONSchemas"`
}
// OpenAPISchemaType is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
//
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
func (_ JSONSchemaPropsOrArray) OpenAPISchemaType() []string {
// TODO: return actual types when anyOf is supported
return nil
}
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
func (_ JSONSchemaPropsOrArray) OpenAPISchemaFormat() string { return "" }
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
// Defaults to true for the boolean property.
type JSONSchemaPropsOrBool struct {
Allows bool `protobuf:"varint,1,opt,name=allows"`
Schema *JSONSchemaProps `protobuf:"bytes,2,opt,name=schema"`
}
// OpenAPISchemaType is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
//
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
func (_ JSONSchemaPropsOrBool) OpenAPISchemaType() []string {
// TODO: return actual types when anyOf is supported
return nil
}
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
func (_ JSONSchemaPropsOrBool) OpenAPISchemaFormat() string { return "" }
// JSONSchemaDependencies represent a dependencies property.
type JSONSchemaDependencies map[string]JSONSchemaPropsOrStringArray
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
type JSONSchemaPropsOrStringArray struct {
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
Property []string `protobuf:"bytes,2,rep,name=property"`
}
// OpenAPISchemaType is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
//
// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
func (_ JSONSchemaPropsOrStringArray) OpenAPISchemaType() []string {
// TODO: return actual types when anyOf is supported
return nil
}
// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
// the OpenAPI spec of this type.
func (_ JSONSchemaPropsOrStringArray) OpenAPISchemaFormat() string { return "" }
// JSONSchemaDefinitions contains the models explicitly defined in this spec.
type JSONSchemaDefinitions map[string]JSONSchemaProps
// ExternalDocumentation allows referencing an external resource for extended documentation.
type ExternalDocumentation struct {
Description string `json:"description,omitempty" protobuf:"bytes,1,opt,name=description"`
URL string `json:"url,omitempty" protobuf:"bytes,2,opt,name=url"`
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,663 @@
// +build !ignore_autogenerated
/*
Copyright The Kubernetes 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConversionRequest) DeepCopyInto(out *ConversionRequest) {
*out = *in
if in.Objects != nil {
in, out := &in.Objects, &out.Objects
*out = make([]runtime.RawExtension, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionRequest.
func (in *ConversionRequest) DeepCopy() *ConversionRequest {
if in == nil {
return nil
}
out := new(ConversionRequest)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConversionResponse) DeepCopyInto(out *ConversionResponse) {
*out = *in
if in.ConvertedObjects != nil {
in, out := &in.ConvertedObjects, &out.ConvertedObjects
*out = make([]runtime.RawExtension, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.Result.DeepCopyInto(&out.Result)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionResponse.
func (in *ConversionResponse) DeepCopy() *ConversionResponse {
if in == nil {
return nil
}
out := new(ConversionResponse)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConversionReview) DeepCopyInto(out *ConversionReview) {
*out = *in
out.TypeMeta = in.TypeMeta
if in.Request != nil {
in, out := &in.Request, &out.Request
*out = new(ConversionRequest)
(*in).DeepCopyInto(*out)
}
if in.Response != nil {
in, out := &in.Response, &out.Response
*out = new(ConversionResponse)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConversionReview.
func (in *ConversionReview) DeepCopy() *ConversionReview {
if in == nil {
return nil
}
out := new(ConversionReview)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ConversionReview) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceColumnDefinition) DeepCopyInto(out *CustomResourceColumnDefinition) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceColumnDefinition.
func (in *CustomResourceColumnDefinition) DeepCopy() *CustomResourceColumnDefinition {
if in == nil {
return nil
}
out := new(CustomResourceColumnDefinition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceConversion) DeepCopyInto(out *CustomResourceConversion) {
*out = *in
if in.Webhook != nil {
in, out := &in.Webhook, &out.Webhook
*out = new(WebhookConversion)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceConversion.
func (in *CustomResourceConversion) DeepCopy() *CustomResourceConversion {
if in == nil {
return nil
}
out := new(CustomResourceConversion)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinition) DeepCopyInto(out *CustomResourceDefinition) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinition.
func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
if in == nil {
return nil
}
out := new(CustomResourceDefinition)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CustomResourceDefinition) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionCondition) DeepCopyInto(out *CustomResourceDefinitionCondition) {
*out = *in
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionCondition.
func (in *CustomResourceDefinitionCondition) DeepCopy() *CustomResourceDefinitionCondition {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionList) DeepCopyInto(out *CustomResourceDefinitionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]CustomResourceDefinition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionList.
func (in *CustomResourceDefinitionList) DeepCopy() *CustomResourceDefinitionList {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CustomResourceDefinitionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionNames) DeepCopyInto(out *CustomResourceDefinitionNames) {
*out = *in
if in.ShortNames != nil {
in, out := &in.ShortNames, &out.ShortNames
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Categories != nil {
in, out := &in.Categories, &out.Categories
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionNames.
func (in *CustomResourceDefinitionNames) DeepCopy() *CustomResourceDefinitionNames {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionNames)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
*out = *in
in.Names.DeepCopyInto(&out.Names)
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]CustomResourceDefinitionVersion, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Conversion != nil {
in, out := &in.Conversion, &out.Conversion
*out = new(CustomResourceConversion)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionSpec.
func (in *CustomResourceDefinitionSpec) DeepCopy() *CustomResourceDefinitionSpec {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionStatus) DeepCopyInto(out *CustomResourceDefinitionStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]CustomResourceDefinitionCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.AcceptedNames.DeepCopyInto(&out.AcceptedNames)
if in.StoredVersions != nil {
in, out := &in.StoredVersions, &out.StoredVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionStatus.
func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionStatus {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionVersion) DeepCopyInto(out *CustomResourceDefinitionVersion) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(CustomResourceValidation)
(*in).DeepCopyInto(*out)
}
if in.Subresources != nil {
in, out := &in.Subresources, &out.Subresources
*out = new(CustomResourceSubresources)
(*in).DeepCopyInto(*out)
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
*out = make([]CustomResourceColumnDefinition, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionVersion.
func (in *CustomResourceDefinitionVersion) DeepCopy() *CustomResourceDefinitionVersion {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionVersion)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresourceScale) DeepCopyInto(out *CustomResourceSubresourceScale) {
*out = *in
if in.LabelSelectorPath != nil {
in, out := &in.LabelSelectorPath, &out.LabelSelectorPath
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceScale.
func (in *CustomResourceSubresourceScale) DeepCopy() *CustomResourceSubresourceScale {
if in == nil {
return nil
}
out := new(CustomResourceSubresourceScale)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresourceStatus) DeepCopyInto(out *CustomResourceSubresourceStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceStatus.
func (in *CustomResourceSubresourceStatus) DeepCopy() *CustomResourceSubresourceStatus {
if in == nil {
return nil
}
out := new(CustomResourceSubresourceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresources) DeepCopyInto(out *CustomResourceSubresources) {
*out = *in
if in.Status != nil {
in, out := &in.Status, &out.Status
*out = new(CustomResourceSubresourceStatus)
**out = **in
}
if in.Scale != nil {
in, out := &in.Scale, &out.Scale
*out = new(CustomResourceSubresourceScale)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresources.
func (in *CustomResourceSubresources) DeepCopy() *CustomResourceSubresources {
if in == nil {
return nil
}
out := new(CustomResourceSubresources)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceValidation) DeepCopyInto(out *CustomResourceValidation) {
*out = *in
if in.OpenAPIV3Schema != nil {
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceValidation.
func (in *CustomResourceValidation) DeepCopy() *CustomResourceValidation {
if in == nil {
return nil
}
out := new(CustomResourceValidation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalDocumentation) DeepCopyInto(out *ExternalDocumentation) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDocumentation.
func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
if in == nil {
return nil
}
out := new(ExternalDocumentation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSON) DeepCopyInto(out *JSON) {
*out = *in
if in.Raw != nil {
in, out := &in.Raw, &out.Raw
*out = make([]byte, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSON.
func (in *JSON) DeepCopy() *JSON {
if in == nil {
return nil
}
out := new(JSON)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in JSONSchemaDefinitions) DeepCopyInto(out *JSONSchemaDefinitions) {
{
in := &in
*out = make(JSONSchemaDefinitions, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDefinitions.
func (in JSONSchemaDefinitions) DeepCopy() JSONSchemaDefinitions {
if in == nil {
return nil
}
out := new(JSONSchemaDefinitions)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in JSONSchemaDependencies) DeepCopyInto(out *JSONSchemaDependencies) {
{
in := &in
*out = make(JSONSchemaDependencies, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDependencies.
func (in JSONSchemaDependencies) DeepCopy() JSONSchemaDependencies {
if in == nil {
return nil
}
out := new(JSONSchemaDependencies)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaProps) DeepCopyInto(out *JSONSchemaProps) {
clone := in.DeepCopy()
*out = *clone
return
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrArray) DeepCopyInto(out *JSONSchemaPropsOrArray) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
if in.JSONSchemas != nil {
in, out := &in.JSONSchemas, &out.JSONSchemas
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrArray.
func (in *JSONSchemaPropsOrArray) DeepCopy() *JSONSchemaPropsOrArray {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrArray)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrBool) DeepCopyInto(out *JSONSchemaPropsOrBool) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrBool.
func (in *JSONSchemaPropsOrBool) DeepCopy() *JSONSchemaPropsOrBool {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrBool)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrStringArray) DeepCopyInto(out *JSONSchemaPropsOrStringArray) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
if in.Property != nil {
in, out := &in.Property, &out.Property
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrStringArray.
func (in *JSONSchemaPropsOrStringArray) DeepCopy() *JSONSchemaPropsOrStringArray {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrStringArray)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceReference) DeepCopyInto(out *ServiceReference) {
*out = *in
if in.Path != nil {
in, out := &in.Path, &out.Path
*out = new(string)
**out = **in
}
if in.Port != nil {
in, out := &in.Port, &out.Port
*out = new(int32)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceReference.
func (in *ServiceReference) DeepCopy() *ServiceReference {
if in == nil {
return nil
}
out := new(ServiceReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WebhookClientConfig) DeepCopyInto(out *WebhookClientConfig) {
*out = *in
if in.URL != nil {
in, out := &in.URL, &out.URL
*out = new(string)
**out = **in
}
if in.Service != nil {
in, out := &in.Service, &out.Service
*out = new(ServiceReference)
(*in).DeepCopyInto(*out)
}
if in.CABundle != nil {
in, out := &in.CABundle, &out.CABundle
*out = make([]byte, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookClientConfig.
func (in *WebhookClientConfig) DeepCopy() *WebhookClientConfig {
if in == nil {
return nil
}
out := new(WebhookClientConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WebhookConversion) DeepCopyInto(out *WebhookConversion) {
*out = *in
if in.ClientConfig != nil {
in, out := &in.ClientConfig, &out.ClientConfig
*out = new(WebhookClientConfig)
(*in).DeepCopyInto(*out)
}
if in.ConversionReviewVersions != nil {
in, out := &in.ConversionReviewVersions, &out.ConversionReviewVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConversion.
func (in *WebhookConversion) DeepCopy() *WebhookConversion {
if in == nil {
return nil
}
out := new(WebhookConversion)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,57 @@
// +build !ignore_autogenerated
/*
Copyright The Kubernetes 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.
*/
// Code generated by defaulter-gen. DO NOT EDIT.
package v1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&CustomResourceDefinition{}, func(obj interface{}) { SetObjectDefaults_CustomResourceDefinition(obj.(*CustomResourceDefinition)) })
scheme.AddTypeDefaultingFunc(&CustomResourceDefinitionList{}, func(obj interface{}) {
SetObjectDefaults_CustomResourceDefinitionList(obj.(*CustomResourceDefinitionList))
})
return nil
}
func SetObjectDefaults_CustomResourceDefinition(in *CustomResourceDefinition) {
SetDefaults_CustomResourceDefinition(in)
SetDefaults_CustomResourceDefinitionSpec(&in.Spec)
if in.Spec.Conversion != nil {
if in.Spec.Conversion.Webhook != nil {
if in.Spec.Conversion.Webhook.ClientConfig != nil {
if in.Spec.Conversion.Webhook.ClientConfig.Service != nil {
SetDefaults_ServiceReference(in.Spec.Conversion.Webhook.ClientConfig.Service)
}
}
}
}
}
func SetObjectDefaults_CustomResourceDefinitionList(in *CustomResourceDefinitionList) {
for i := range in.Items {
a := &in.Items[i]
SetObjectDefaults_CustomResourceDefinition(a)
}
}

View File

@ -0,0 +1,554 @@
// +build !ignore_autogenerated
/*
Copyright The Kubernetes 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.
*/
// Code generated by deepcopy-gen. DO NOT EDIT.
package apiextensions
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceColumnDefinition) DeepCopyInto(out *CustomResourceColumnDefinition) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceColumnDefinition.
func (in *CustomResourceColumnDefinition) DeepCopy() *CustomResourceColumnDefinition {
if in == nil {
return nil
}
out := new(CustomResourceColumnDefinition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceConversion) DeepCopyInto(out *CustomResourceConversion) {
*out = *in
if in.WebhookClientConfig != nil {
in, out := &in.WebhookClientConfig, &out.WebhookClientConfig
*out = new(WebhookClientConfig)
(*in).DeepCopyInto(*out)
}
if in.ConversionReviewVersions != nil {
in, out := &in.ConversionReviewVersions, &out.ConversionReviewVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceConversion.
func (in *CustomResourceConversion) DeepCopy() *CustomResourceConversion {
if in == nil {
return nil
}
out := new(CustomResourceConversion)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinition) DeepCopyInto(out *CustomResourceDefinition) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinition.
func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
if in == nil {
return nil
}
out := new(CustomResourceDefinition)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CustomResourceDefinition) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionCondition) DeepCopyInto(out *CustomResourceDefinitionCondition) {
*out = *in
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionCondition.
func (in *CustomResourceDefinitionCondition) DeepCopy() *CustomResourceDefinitionCondition {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionList) DeepCopyInto(out *CustomResourceDefinitionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]CustomResourceDefinition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionList.
func (in *CustomResourceDefinitionList) DeepCopy() *CustomResourceDefinitionList {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *CustomResourceDefinitionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionNames) DeepCopyInto(out *CustomResourceDefinitionNames) {
*out = *in
if in.ShortNames != nil {
in, out := &in.ShortNames, &out.ShortNames
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Categories != nil {
in, out := &in.Categories, &out.Categories
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionNames.
func (in *CustomResourceDefinitionNames) DeepCopy() *CustomResourceDefinitionNames {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionNames)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
*out = *in
in.Names.DeepCopyInto(&out.Names)
if in.Validation != nil {
in, out := &in.Validation, &out.Validation
*out = new(CustomResourceValidation)
(*in).DeepCopyInto(*out)
}
if in.Subresources != nil {
in, out := &in.Subresources, &out.Subresources
*out = new(CustomResourceSubresources)
(*in).DeepCopyInto(*out)
}
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]CustomResourceDefinitionVersion, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
*out = make([]CustomResourceColumnDefinition, len(*in))
copy(*out, *in)
}
if in.Conversion != nil {
in, out := &in.Conversion, &out.Conversion
*out = new(CustomResourceConversion)
(*in).DeepCopyInto(*out)
}
if in.PreserveUnknownFields != nil {
in, out := &in.PreserveUnknownFields, &out.PreserveUnknownFields
*out = new(bool)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionSpec.
func (in *CustomResourceDefinitionSpec) DeepCopy() *CustomResourceDefinitionSpec {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionStatus) DeepCopyInto(out *CustomResourceDefinitionStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]CustomResourceDefinitionCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.AcceptedNames.DeepCopyInto(&out.AcceptedNames)
if in.StoredVersions != nil {
in, out := &in.StoredVersions, &out.StoredVersions
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionStatus.
func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionStatus {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionVersion) DeepCopyInto(out *CustomResourceDefinitionVersion) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(CustomResourceValidation)
(*in).DeepCopyInto(*out)
}
if in.Subresources != nil {
in, out := &in.Subresources, &out.Subresources
*out = new(CustomResourceSubresources)
(*in).DeepCopyInto(*out)
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
*out = make([]CustomResourceColumnDefinition, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceDefinitionVersion.
func (in *CustomResourceDefinitionVersion) DeepCopy() *CustomResourceDefinitionVersion {
if in == nil {
return nil
}
out := new(CustomResourceDefinitionVersion)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresourceScale) DeepCopyInto(out *CustomResourceSubresourceScale) {
*out = *in
if in.LabelSelectorPath != nil {
in, out := &in.LabelSelectorPath, &out.LabelSelectorPath
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceScale.
func (in *CustomResourceSubresourceScale) DeepCopy() *CustomResourceSubresourceScale {
if in == nil {
return nil
}
out := new(CustomResourceSubresourceScale)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresourceStatus) DeepCopyInto(out *CustomResourceSubresourceStatus) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresourceStatus.
func (in *CustomResourceSubresourceStatus) DeepCopy() *CustomResourceSubresourceStatus {
if in == nil {
return nil
}
out := new(CustomResourceSubresourceStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceSubresources) DeepCopyInto(out *CustomResourceSubresources) {
*out = *in
if in.Status != nil {
in, out := &in.Status, &out.Status
*out = new(CustomResourceSubresourceStatus)
**out = **in
}
if in.Scale != nil {
in, out := &in.Scale, &out.Scale
*out = new(CustomResourceSubresourceScale)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceSubresources.
func (in *CustomResourceSubresources) DeepCopy() *CustomResourceSubresources {
if in == nil {
return nil
}
out := new(CustomResourceSubresources)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceValidation) DeepCopyInto(out *CustomResourceValidation) {
*out = *in
if in.OpenAPIV3Schema != nil {
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceValidation.
func (in *CustomResourceValidation) DeepCopy() *CustomResourceValidation {
if in == nil {
return nil
}
out := new(CustomResourceValidation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ExternalDocumentation) DeepCopyInto(out *ExternalDocumentation) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDocumentation.
func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
if in == nil {
return nil
}
out := new(ExternalDocumentation)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in JSONSchemaDefinitions) DeepCopyInto(out *JSONSchemaDefinitions) {
{
in := &in
*out = make(JSONSchemaDefinitions, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDefinitions.
func (in JSONSchemaDefinitions) DeepCopy() JSONSchemaDefinitions {
if in == nil {
return nil
}
out := new(JSONSchemaDefinitions)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in JSONSchemaDependencies) DeepCopyInto(out *JSONSchemaDependencies) {
{
in := &in
*out = make(JSONSchemaDependencies, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
return
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaDependencies.
func (in JSONSchemaDependencies) DeepCopy() JSONSchemaDependencies {
if in == nil {
return nil
}
out := new(JSONSchemaDependencies)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaProps) DeepCopyInto(out *JSONSchemaProps) {
clone := in.DeepCopy()
*out = *clone
return
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrArray) DeepCopyInto(out *JSONSchemaPropsOrArray) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
if in.JSONSchemas != nil {
in, out := &in.JSONSchemas, &out.JSONSchemas
*out = make([]JSONSchemaProps, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrArray.
func (in *JSONSchemaPropsOrArray) DeepCopy() *JSONSchemaPropsOrArray {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrArray)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrBool) DeepCopyInto(out *JSONSchemaPropsOrBool) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrBool.
func (in *JSONSchemaPropsOrBool) DeepCopy() *JSONSchemaPropsOrBool {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrBool)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JSONSchemaPropsOrStringArray) DeepCopyInto(out *JSONSchemaPropsOrStringArray) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = (*in).DeepCopy()
}
if in.Property != nil {
in, out := &in.Property, &out.Property
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrStringArray.
func (in *JSONSchemaPropsOrStringArray) DeepCopy() *JSONSchemaPropsOrStringArray {
if in == nil {
return nil
}
out := new(JSONSchemaPropsOrStringArray)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceReference) DeepCopyInto(out *ServiceReference) {
*out = *in
if in.Path != nil {
in, out := &in.Path, &out.Path
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceReference.
func (in *ServiceReference) DeepCopy() *ServiceReference {
if in == nil {
return nil
}
out := new(ServiceReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WebhookClientConfig) DeepCopyInto(out *WebhookClientConfig) {
*out = *in
if in.URL != nil {
in, out := &in.URL, &out.URL
*out = new(string)
**out = **in
}
if in.Service != nil {
in, out := &in.Service, &out.Service
*out = new(ServiceReference)
(*in).DeepCopyInto(*out)
}
if in.CABundle != nil {
in, out := &in.CABundle, &out.CABundle
*out = make([]byte, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookClientConfig.
func (in *WebhookClientConfig) DeepCopy() *WebhookClientConfig {
if in == nil {
return nil
}
out := new(WebhookClientConfig)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,49 @@
/*
Copyright 2014 The Kubernetes 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 equality
import (
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
)
// Semantic can do semantic deep equality checks for api objects.
// Example: apiequality.Semantic.DeepEqual(aPod, aPodWithNonNilButEmptyMaps) == true
var Semantic = conversion.EqualitiesOrDie(
func(a, b resource.Quantity) bool {
// Ignore formatting, only care that numeric value stayed the same.
// TODO: if we decide it's important, it should be safe to start comparing the format.
//
// Uninitialized quantities are equivalent to 0 quantities.
return a.Cmp(b) == 0
},
func(a, b metav1.MicroTime) bool {
return a.UTC() == b.UTC()
},
func(a, b metav1.Time) bool {
return a.UTC() == b.UTC()
},
func(a, b labels.Selector) bool {
return a.String() == b.String()
},
func(a, b fields.Selector) bool {
return a.String() == b.String()
},
)

10
vendor/k8s.io/utils/pointer/OWNERS generated vendored Normal file
View File

@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- apelisse
- stewart-yu
- thockin
reviewers:
- apelisse
- stewart-yu
- thockin

86
vendor/k8s.io/utils/pointer/pointer.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
/*
Copyright 2018 The Kubernetes 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 pointer
import (
"fmt"
"reflect"
)
// AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when,
// for example, an API struct is handled by plugins which need to distinguish
// "no plugin accepted this spec" from "this spec is empty".
//
// This function is only valid for structs and pointers to structs. Any other
// type will cause a panic. Passing a typed nil pointer will return true.
func AllPtrFieldsNil(obj interface{}) bool {
v := reflect.ValueOf(obj)
if !v.IsValid() {
panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj))
}
if v.Kind() == reflect.Ptr {
if v.IsNil() {
return true
}
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() {
return false
}
}
return true
}
// Int32Ptr returns a pointer to an int32
func Int32Ptr(i int32) *int32 {
return &i
}
// Int64Ptr returns a pointer to an int64
func Int64Ptr(i int64) *int64 {
return &i
}
// Int32PtrDerefOr dereference the int32 ptr and returns it if not nil,
// else returns def.
func Int32PtrDerefOr(ptr *int32, def int32) int32 {
if ptr != nil {
return *ptr
}
return def
}
// BoolPtr returns a pointer to a bool
func BoolPtr(b bool) *bool {
return &b
}
// StringPtr returns a pointer to the passed string.
func StringPtr(s string) *string {
return &s
}
// Float32Ptr returns a pointer to the passed float32.
func Float32Ptr(i float32) *float32 {
return &i
}
// Float64Ptr returns a pointer to the passed float64.
func Float64Ptr(i float64) *float64 {
return &i
}

9
vendor/modules.txt vendored
View File

@ -172,7 +172,7 @@ gopkg.in/alecthomas/kingpin.v2
gopkg.in/fsnotify.v1
# gopkg.in/inf.v0 v0.9.1
gopkg.in/inf.v0
# gopkg.in/yaml.v2 v2.2.8
# gopkg.in/yaml.v2 v2.2.5
gopkg.in/yaml.v2
# k8s.io/api v0.18.2 => k8s.io/api v0.0.0-20191016110408-35e52d86657a
k8s.io/api/admission/v1beta1
@ -214,7 +214,11 @@ k8s.io/api/settings/v1alpha1
k8s.io/api/storage/v1
k8s.io/api/storage/v1alpha1
k8s.io/api/storage/v1beta1
# k8s.io/apiextensions-apiserver v0.18.2 => k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
# k8s.io/apimachinery v0.18.2 => k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8
k8s.io/apimachinery/pkg/api/equality
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/meta
k8s.io/apimachinery/pkg/api/resource
@ -388,6 +392,7 @@ k8s.io/kube-openapi/pkg/util/proto
# k8s.io/utils v0.0.0-20191010214722-8d271d903fe4
k8s.io/utils/buffer
k8s.io/utils/integer
k8s.io/utils/pointer
k8s.io/utils/trace
# sigs.k8s.io/controller-runtime v0.6.0 => sigs.k8s.io/controller-runtime v0.4.0
sigs.k8s.io/controller-runtime/pkg/cache
@ -423,5 +428,5 @@ sigs.k8s.io/controller-runtime/pkg/webhook
sigs.k8s.io/controller-runtime/pkg/webhook/admission
sigs.k8s.io/controller-runtime/pkg/webhook/internal/certwatcher
sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics
# sigs.k8s.io/yaml v1.2.0
# sigs.k8s.io/yaml v1.2.0 => sigs.k8s.io/yaml v1.1.0
sigs.k8s.io/yaml

15
vendor/sigs.k8s.io/yaml/.travis.yml generated vendored
View File

@ -1,13 +1,14 @@
language: go
dist: xenial
go:
- 1.12.x
- 1.13.x
- 1.9.x
- 1.10.x
- 1.11.x
script:
- diff -u <(echo -n) <(gofmt -d *.go)
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- diff -u <(echo -n) <(golint $(go list -e ./...) | grep -v YAMLToJSON)
- GO111MODULE=on go vet .
- GO111MODULE=on go test -v -race ./...
- git diff --exit-code
- go tool vet .
- go test -v -race ./...
install:
- GO111MODULE=off go get golang.org/x/lint/golint
- go get golang.org/x/lint/golint

2
vendor/sigs.k8s.io/yaml/OWNERS generated vendored
View File

@ -1,5 +1,3 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- dims
- lavalamp

14
vendor/sigs.k8s.io/yaml/README.md generated vendored
View File

@ -1,14 +1,12 @@
# YAML marshaling and unmarshaling support for Go
[![Build Status](https://travis-ci.org/kubernetes-sigs/yaml.svg)](https://travis-ci.org/kubernetes-sigs/yaml)
kubernetes-sigs/yaml is a permanent fork of [ghodss/yaml](https://github.com/ghodss/yaml).
[![Build Status](https://travis-ci.org/ghodss/yaml.svg)](https://travis-ci.org/ghodss/yaml)
## Introduction
A wrapper around [go-yaml](https://github.com/go-yaml/yaml) designed to enable a better way of handling YAML when marshaling to and from structs.
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://web.archive.org/web/20190603050330/http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
In short, this library first converts YAML to JSON using go-yaml and then uses `json.Marshal` and `json.Unmarshal` to convert to or from the struct. This means that it effectively reuses the JSON struct tags as well as the custom JSON methods `MarshalJSON` and `UnmarshalJSON` unlike go-yaml. For a detailed overview of the rationale behind this method, [see this blog post](http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/).
## Compatibility
@ -34,13 +32,13 @@ GOOD:
To install, run:
```
$ go get sigs.k8s.io/yaml
$ go get github.com/ghodss/yaml
```
And import using:
```
import "sigs.k8s.io/yaml"
import "github.com/ghodss/yaml"
```
Usage is very similar to the JSON library:
@ -51,7 +49,7 @@ package main
import (
"fmt"
"sigs.k8s.io/yaml"
"github.com/ghodss/yaml"
)
type Person struct {
@ -95,7 +93,7 @@ package main
import (
"fmt"
"sigs.k8s.io/yaml"
"github.com/ghodss/yaml"
)
func main() {

8
vendor/sigs.k8s.io/yaml/go.mod generated vendored
View File

@ -1,8 +0,0 @@
module sigs.k8s.io/yaml
go 1.12
require (
github.com/davecgh/go-spew v1.1.1
gopkg.in/yaml.v2 v2.2.8
)

9
vendor/sigs.k8s.io/yaml/go.sum generated vendored
View File

@ -1,9 +0,0 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

61
vendor/sigs.k8s.io/yaml/yaml.go generated vendored
View File

@ -317,64 +317,3 @@ func convertToJSONableObject(yamlObj interface{}, jsonTarget *reflect.Value) (in
return yamlObj, nil
}
}
// JSONObjectToYAMLObject converts an in-memory JSON object into a YAML in-memory MapSlice,
// without going through a byte representation. A nil or empty map[string]interface{} input is
// converted to an empty map, i.e. yaml.MapSlice(nil).
//
// interface{} slices stay interface{} slices. map[string]interface{} becomes yaml.MapSlice.
//
// int64 and float64 are down casted following the logic of github.com/go-yaml/yaml:
// - float64s are down-casted as far as possible without data-loss to int, int64, uint64.
// - int64s are down-casted to int if possible without data-loss.
//
// Big int/int64/uint64 do not lose precision as in the json-yaml roundtripping case.
//
// string, bool and any other types are unchanged.
func JSONObjectToYAMLObject(j map[string]interface{}) yaml.MapSlice {
if len(j) == 0 {
return nil
}
ret := make(yaml.MapSlice, 0, len(j))
for k, v := range j {
ret = append(ret, yaml.MapItem{Key: k, Value: jsonToYAMLValue(v)})
}
return ret
}
func jsonToYAMLValue(j interface{}) interface{} {
switch j := j.(type) {
case map[string]interface{}:
if j == nil {
return interface{}(nil)
}
return JSONObjectToYAMLObject(j)
case []interface{}:
if j == nil {
return interface{}(nil)
}
ret := make([]interface{}, len(j))
for i := range j {
ret[i] = jsonToYAMLValue(j[i])
}
return ret
case float64:
// replicate the logic in https://github.com/go-yaml/yaml/blob/51d6538a90f86fe93ac480b35f37b2be17fef232/resolve.go#L151
if i64 := int64(j); j == float64(i64) {
if i := int(i64); i64 == int64(i) {
return i
}
return i64
}
if ui64 := uint64(j); j == float64(ui64) {
return ui64
}
return j
case int64:
if i := int(j); j == int64(i) {
return i
}
return j
}
return j
}