diff --git a/.github/workflows/clusterkubevirtadm-test.yaml b/.github/workflows/clusterkubevirtadm-test.yaml index 9a9afdbb0..e83f967c3 100644 --- a/.github/workflows/clusterkubevirtadm-test.yaml +++ b/.github/workflows/clusterkubevirtadm-test.yaml @@ -15,7 +15,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.17 + go-version: 1.18 - name: Checkout code uses: actions/checkout@v2 - name: Test diff --git a/.github/workflows/create_release.yaml b/.github/workflows/create_release.yaml new file mode 100644 index 000000000..5aaa24a2c --- /dev/null +++ b/.github/workflows/create_release.yaml @@ -0,0 +1,73 @@ +on: + push: + tags: + - "v*" + +name: Upload Release Asset + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: build image + shell: bash + env: + QUAY_TOKEN: ${{secrets.QUAY_TOKEN}} + REGISTRY: "quay.io/capk" + TAG: ${{ github.ref_name }} + run: | + echo $QUAY_TOKEN | docker login -u="capk+capk_robot" quay.io --password-stdin + make docker-build + make docker-push + build: + name: Upload Release Asset + needs: build-and-push-image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: '1.18' + - name: Install kustomize + run: curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash + - name: Create infrastructure components + env: + REGISTRY: "quay.io/capk" + IMAGE_NAME: "capk-manager-amd64" + TAG: ${{ github.ref_name }} + run: | + make create-infrastructure-components + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + - name: Upload infrastructure-components.yaml + id: upload-infrastructure-components + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./infrastructure-components.yaml + asset_name: infrastructure-components.yaml + asset_content_type: text/plain + - name: Upload metadata.yaml + id: upload-metadata + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: ./metadata.yaml + asset_name: metadata.yaml + asset_content_type: text/plain \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 02d2c1fd2..cbed17021 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -5,7 +5,7 @@ jobs: if: (github.repository == 'kubernetes-sigs/cluster-api-provider-kubevirt') strategy: matrix: - go-version: [1.17.x] + go-version: [1.18.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -27,7 +27,7 @@ jobs: - name: Install Go uses: actions/setup-go@v2 with: - go-version: 1.17.x + go-version: 1.18.x - name: Checkout code uses: actions/checkout@v2 - name: Test with coverage diff --git a/.gitignore b/.gitignore index 04cb57a9d..b3107d924 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ cluster-up/ hack/tools/bin/ bin/ .idea/ +infrastructure-components.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 182c774cf..a51350f3c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ # Build the manager binary # Run this with docker build --build-arg builder_image= -ARG builder_image=golang:1.17.2 +ARG builder_image=golang:1.18.2 FROM ${builder_image} as builder WORKDIR /workspace diff --git a/Makefile b/Makefile index e2da4a873..420805519 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ # If you update this file, please follow: # https://suva.sh/posts/well-documented-makefiles/ -ROOT = $$GOPATH/pkg/mod/sigs.k8s.io/cluster-api@v0.3.11-0.20210525210043-6c7878e7b4a9 +ROOT = $$(go env GOPATH)/pkg/mod/sigs.k8s.io/cluster-api@v0.3.11-0.20210525210043-6c7878e7b4a9 .DEFAULT_GOAL:=help TARGET ?= target @@ -50,13 +50,11 @@ endif CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/controller-gen) CONVERSION_GEN := $(abspath $(TOOLS_BIN_DIR)/conversion-gen) GOTESTSUM := $(abspath $(TOOLS_BIN_DIR)/gotestsum) -KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/kustomize) - -$(KUSTOMIZE): # Build kustomize from tools folder. - $(MAKE) -C $(ROOT) kustomize +KUSTOMIZE_IMAGE = k8s.gcr.io/kustomize/kustomize:v3.8.7 +KUSTOMIZE ?= docker run $(KUSTOMIZE_IMAGE) # Define Docker related variables. Releases should modify and double check these vars. -REGISTRY ?= localhost:5000 +REGISTRY ?= 127.0.0.1:5000 IMAGE_NAME ?= capk-manager CONTROLLER_IMG ?= $(REGISTRY)/$(IMAGE_NAME) ARCH ?= amd64 @@ -187,7 +185,7 @@ modules: ## Runs go mod to ensure modules are up to date. .PHONY: docker-pull-prerequisites docker-pull-prerequisites: docker pull docker.io/docker/dockerfile:1.1-experimental - docker pull docker.io/library/golang:1.17.2 + docker pull docker.io/library/golang:1.18.2 docker pull gcr.io/distroless/static:latest .PHONY: docker-build @@ -244,6 +242,18 @@ else sed -i -e 's@imagePullPolicy: .*@imagePullPolicy: '"$(PULL_POLICY)"'@' ./config/default/manager_pull_policy.yaml endif +## -------------------------------------- +## Deployment +## -------------------------------------- +##> infrastructure-components.yaml +set_controller_image: + echo setting controller image to be ${CONTROLLER_IMG}:${TAG} + cd config/default && kustomize edit set image controller=${CONTROLLER_IMG}:${TAG} + +create-infrastructure-components: generate-manifests set_controller_image + kustomize build config/default > infrastructure-components.yaml + + ## -------------------------------------- ## Cleanup / Verification ## -------------------------------------- diff --git a/api/v1alpha1/kubevirtcluster_types.go b/api/v1alpha1/kubevirtcluster_types.go index 4dffb9667..c07f0701b 100644 --- a/api/v1alpha1/kubevirtcluster_types.go +++ b/api/v1alpha1/kubevirtcluster_types.go @@ -28,13 +28,17 @@ const ( ClusterFinalizer = "kubevirtcluster.infrastructure.cluster.x-k8s.io" ) -const ( +const ( //labels KubevirtMachineNameLabel = "capk.cluster.x-k8s.io/kubevirt-machine-name" KubevirtMachineNamespaceLabel = "capk.cluster.x-k8s.io/kubevirt-machine-namespace" KubevirtMachineVMTerminalLabel = "capk.cluster.x-k8s.io/vm-is-terminal" ) +const ( // annotations + VmiDeletionGraceTime = "capk.cluster.x-k8s.io/vmi-deletion-grace-time" +) + // KubevirtClusterSpec defines the desired state of KubevirtCluster. type KubevirtClusterSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 27dfaab16..41062cfd6 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/clusterctl-settings.json b/clusterctl-settings.json index 7f22cd69e..9a0b7e406 100644 --- a/clusterctl-settings.json +++ b/clusterctl-settings.json @@ -1,5 +1,5 @@ { - "name": "infrastructure-kubevirt", + "name": "kubevirt", "config": { "componentsFile": "infrastructure-components.yaml", "nextVersion": "v0.1.0" diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachines.yaml index 9aac02628..6fc7cea7f 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachines.yaml @@ -163,18 +163,18 @@ spec: description: PVC is the PVC specification properties: accessModes: - description: 'AccessModes contains the desired + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' items: type: string type: array dataSource: - description: 'This field can be used to specify - either: * An existing VolumeSnapshot object - (snapshot.storage.k8s.io/VolumeSnapshot) * - An existing PVC (PersistentVolumeClaim) If - the provisioner or an external controller + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. If the AnyVolumeDataSource @@ -202,17 +202,17 @@ spec: - name type: object dataSourceRef: - description: 'Specifies the object from which - to populate the volume with data, if a non-empty - volume is desired. This may be any local object - from a non-empty API group (non core object) - or a PersistentVolumeClaim object. When this - field is specified, volume binding will only - succeed if the type of the specified object - matches some installed volume populator or - dynamic provisioner. This field will replace - the functionality of the DataSource field - and as such if both fields are non-empty, + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any local object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, volume + binding will only succeed if the type of the + specified object matches some installed volume + populator or dynamic provisioner. This field + will replace the functionality of the DataSource + field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, both fields (DataSource and DataSourceRef) will be set to the same value @@ -225,7 +225,7 @@ spec: objects. * While DataSource ignores disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed - value is specified. (Alpha) Using this field + value is specified. (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.' properties: @@ -249,7 +249,7 @@ spec: - name type: object resources: - description: 'Resources represents the minimum + description: 'resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than @@ -284,8 +284,8 @@ spec: type: object type: object selector: - description: A label query over volumes to consider - for binding. + description: selector is a label query over + volumes to consider for binding. properties: matchExpressions: description: matchExpressions is a list @@ -336,8 +336,9 @@ spec: type: object type: object storageClassName: - description: 'Name of the StorageClass required - by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' type: string volumeMode: description: volumeMode defines what type of @@ -346,7 +347,7 @@ spec: claim spec. type: string volumeName: - description: VolumeName is the binding reference + description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string type: object @@ -707,9 +708,22 @@ spec: description: Name is the name of the VirtualMachineFlavor or VirtualMachineClusterFlavor type: string - profile: - description: Profile is the name of a custom profile in - the flavor. If left empty, the default profile is used. + required: + - name + type: object + preference: + description: PreferenceMatcher references a set of preference + that is used to fill fields in Template + properties: + kind: + description: 'Kind specifies which preference resource + is referenced. Allowed values are: "VirtualMachinePreference" + and "VirtualMachineClusterPreference". If not specified, + "VirtualMachineClusterPreference" is used by default.' + type: string + name: + description: Name is the name of the VirtualMachinePreference + or VirtualMachineClusterPreference type: string required: - name @@ -1200,9 +1214,6 @@ spec: or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - This field is beta-level and is - only honored when PodAffinityNamespaceSelector - feature is enabled. properties: matchExpressions: description: matchExpressions @@ -1273,7 +1284,7 @@ spec: field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -1397,10 +1408,7 @@ spec: field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) - matches all namespaces. This field - is beta-level and is only honored - when PodAffinityNamespaceSelector - feature is enabled. + matches all namespaces. properties: matchExpressions: description: matchExpressions is @@ -1466,7 +1474,7 @@ spec: in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -1594,9 +1602,6 @@ spec: or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. - This field is beta-level and is - only honored when PodAffinityNamespaceSelector - feature is enabled. properties: matchExpressions: description: matchExpressions @@ -1667,7 +1672,7 @@ spec: field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -1791,10 +1796,7 @@ spec: field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) - matches all namespaces. This field - is beta-level and is only honored - when PodAffinityNamespaceSelector - feature is enabled. + matches all namespaces. properties: matchExpressions: description: matchExpressions is @@ -1860,7 +1862,7 @@ spec: in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -2472,6 +2474,8 @@ spec: boot order are not tried. type: integer bridge: + description: InterfaceBridge connects + to a given network via a linux bridge. type: object dhcpOptions: description: If specified the network @@ -2526,8 +2530,15 @@ spec: DE-AD-00-00-BE-AF.' type: string macvtap: + description: InterfaceMacvtap connects + to a given network by extending the + Kubernetes node's L2 networks via + a macvtap interface. type: object masquerade: + description: InterfaceMasquerade connects + to a given network using netfilter + rules to nat the traffic. type: object model: description: 'Interface model. One of: @@ -2583,8 +2594,14 @@ spec: type: object type: array slirp: + description: InterfaceSlirp connects + to a given network using QEMU user + networking mode. type: object sriov: + description: InterfaceSRIOV connects + to a given network by passing-through + an SR-IOV PCI device via vfio. type: object tag: description: If specified, the virtual @@ -2625,6 +2642,9 @@ spec: required: - name type: object + tpm: + description: Whether to emulate a TPM device. + type: object useVirtioTransitional: description: Fall back to legacy virtio 0.9 support if virtio bus is selected on devices. @@ -3799,14 +3819,15 @@ spec: to the vmi via qemu. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the name + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' type: string readOnly: - description: Will force the ReadOnly - setting in VolumeMounts. Default false. + description: readOnly Will force the + ReadOnly setting in VolumeMounts. + Default false. type: boolean required: - claimName @@ -3840,6 +3861,28 @@ spec: - path - type type: object + memoryDump: + description: MemoryDump is attached to the virt + launcher and is populated with a memory dump + of the vmi + properties: + claimName: + description: 'claimName is the name of a + PersistentVolumeClaim in the same namespace + as the pod using this volume. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + hotpluggable: + description: Hotpluggable indicates whether + the volume can be hotplugged and hotunplugged. + type: boolean + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object name: description: 'Volume''s name. Must be a DNS_LABEL and unique within the vmi. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' @@ -3851,7 +3894,7 @@ spec: the vmi via qemu. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the name of a + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' @@ -3861,8 +3904,8 @@ spec: the volume can be hotplugged and hotunplugged. type: boolean readOnly: - description: Will force the ReadOnly setting - in VolumeMounts. Default false. + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. type: boolean required: - claimName diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachinetemplates.yaml index f16262634..2e4fc36df 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_kubevirtmachinetemplates.yaml @@ -181,16 +181,16 @@ spec: description: PVC is the PVC specification properties: accessModes: - description: 'AccessModes contains the + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' items: type: string type: array dataSource: - description: 'This field can be used - to specify either: * An existing VolumeSnapshot - object (snapshot.storage.k8s.io/VolumeSnapshot) + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified @@ -223,18 +223,18 @@ spec: - name type: object dataSourceRef: - description: 'Specifies the object from - which to populate the volume with - data, if a non-empty volume is desired. - This may be any local object from - a non-empty API group (non core object) - or a PersistentVolumeClaim object. - When this field is specified, volume - binding will only succeed if the type - of the specified object matches some - installed volume populator or dynamic - provisioner. This field will replace - the functionality of the DataSource + description: 'dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + local object from a non-empty API + group (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed if + the type of the specified object matches + some installed volume populator or + dynamic provisioner. This field will + replace the functionality of the DataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, @@ -251,7 +251,7 @@ spec: disallowed values (dropping them), DataSourceRef preserves all values, and generates an error if a disallowed - value is specified. (Alpha) Using + value is specified. (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.' properties: @@ -277,7 +277,7 @@ spec: - name type: object resources: - description: 'Resources represents the + description: 'resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed @@ -316,8 +316,8 @@ spec: type: object type: object selector: - description: A label query over volumes - to consider for binding. + description: selector is a label query + over volumes to consider for binding. properties: matchExpressions: description: matchExpressions is @@ -376,9 +376,9 @@ spec: type: object type: object storageClassName: - description: 'Name of the StorageClass - required by the claim. More info: - https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: 'storageClassName is the + name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' type: string volumeMode: description: volumeMode defines what @@ -387,7 +387,7 @@ spec: when not included in claim spec. type: string volumeName: - description: VolumeName is the binding + description: volumeName is the binding reference to the PersistentVolume backing this claim. type: string @@ -787,10 +787,23 @@ spec: description: Name is the name of the VirtualMachineFlavor or VirtualMachineClusterFlavor type: string - profile: - description: Profile is the name of a custom profile - in the flavor. If left empty, the default profile - is used. + required: + - name + type: object + preference: + description: PreferenceMatcher references a set of + preference that is used to fill fields in Template + properties: + kind: + description: 'Kind specifies which preference + resource is referenced. Allowed values are: + "VirtualMachinePreference" and "VirtualMachineClusterPreference". + If not specified, "VirtualMachineClusterPreference" + is used by default.' + type: string + name: + description: Name is the name of the VirtualMachinePreference + or VirtualMachineClusterPreference type: string required: - name @@ -1365,10 +1378,6 @@ spec: means "this pod's namespace". An empty selector ({}) matches all namespaces. - This field is beta-level - and is only honored when - PodAffinityNamespaceSelector - feature is enabled. properties: matchExpressions: description: matchExpressions @@ -1455,7 +1464,7 @@ spec: the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -1600,10 +1609,7 @@ spec: namespaces list means "this pod's namespace". An empty selector ({}) matches all - namespaces. This field is - beta-level and is only honored - when PodAffinityNamespaceSelector - feature is enabled. + namespaces. properties: matchExpressions: description: matchExpressions @@ -1681,7 +1687,7 @@ spec: ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -1834,10 +1840,6 @@ spec: means "this pod's namespace". An empty selector ({}) matches all namespaces. - This field is beta-level - and is only honored when - PodAffinityNamespaceSelector - feature is enabled. properties: matchExpressions: description: matchExpressions @@ -1924,7 +1926,7 @@ spec: the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -2069,10 +2071,7 @@ spec: namespaces list means "this pod's namespace". An empty selector ({}) matches all - namespaces. This field is - beta-level and is only honored - when PodAffinityNamespaceSelector - feature is enabled. + namespaces. properties: matchExpressions: description: matchExpressions @@ -2150,7 +2149,7 @@ spec: ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector - means "this pod's namespace" + means "this pod's namespace". items: type: string type: array @@ -2833,6 +2832,9 @@ spec: order are not tried. type: integer bridge: + description: InterfaceBridge + connects to a given network + via a linux bridge. type: object dhcpOptions: description: If specified the @@ -2891,8 +2893,17 @@ spec: or DE-AD-00-00-BE-AF.' type: string macvtap: + description: InterfaceMacvtap + connects to a given network + by extending the Kubernetes + node's L2 networks via a macvtap + interface. type: object masquerade: + description: InterfaceMasquerade + connects to a given network + using netfilter rules to nat + the traffic. type: object model: description: 'Interface model. @@ -2957,8 +2968,16 @@ spec: type: object type: array slirp: + description: InterfaceSlirp + connects to a given network + using QEMU user networking + mode. type: object sriov: + description: InterfaceSRIOV + connects to a given network + by passing-through an SR-IOV + PCI device via vfio. type: object tag: description: If specified, the @@ -3003,6 +3022,10 @@ spec: required: - name type: object + tpm: + description: Whether to emulate a + TPM device. + type: object useVirtioTransitional: description: Fall back to legacy virtio 0.9 support if virtio bus is selected @@ -4285,15 +4308,15 @@ spec: More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' type: string readOnly: - description: Will force the - ReadOnly setting in VolumeMounts. + description: readOnly Will force + the ReadOnly setting in VolumeMounts. Default false. type: boolean required: @@ -4330,6 +4353,31 @@ spec: - path - type type: object + memoryDump: + description: MemoryDump is attached + to the virt launcher and is populated + with a memory dump of the vmi + properties: + claimName: + description: 'claimName is the name + of a PersistentVolumeClaim in + the same namespace as the pod + using this volume. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + hotpluggable: + description: Hotpluggable indicates + whether the volume can be hotplugged + and hotunplugged. + type: boolean + readOnly: + description: readOnly Will force + the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object name: description: 'Volume''s name. Must be a DNS_LABEL and unique within the @@ -4342,7 +4390,7 @@ spec: to the vmi via qemu. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' properties: claimName: - description: 'ClaimName is the name + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: @@ -4354,9 +4402,9 @@ spec: and hotunplugged. type: boolean readOnly: - description: Will force the ReadOnly - setting in VolumeMounts. Default - false. + description: readOnly Will force + the ReadOnly setting in VolumeMounts. + Default false. type: boolean required: - claimName diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 81b7d4569..bcaede6b6 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -1,4 +1,9 @@ commonLabels: + cluster.x-k8s.io/provider: kubevirt + cluster.x-k8s.io/v1alpha1: v1alpha1 + cluster.x-k8s.io/v1alpha2: v1alpha1 + cluster.x-k8s.io/v1alpha3: v1alpha1 + cluster.x-k8s.io/v1alpha4: v1alpha1 cluster.x-k8s.io/v1beta1: v1alpha1 # This kustomization.yaml is not intended to be run by itself, diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index d9bbb1f63..035dc18e8 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -3,7 +3,12 @@ namespace: capk-system namePrefix: capk- commonLabels: - cluster.x-k8s.io/provider: "infrastructure-kubevirt" + cluster.x-k8s.io/provider: "kubevirt" + cluster.x-k8s.io/v1alpha1: v1alpha1 + cluster.x-k8s.io/v1alpha2: v1alpha1 + cluster.x-k8s.io/v1alpha3: v1alpha1 + cluster.x-k8s.io/v1alpha4: v1alpha1 + cluster.x-k8s.io/v1beta1: v1alpha1 resources: - namespace.yaml diff --git a/config/default/manager_image_patch.yaml b/config/default/manager_image_patch.yaml index 25419e08c..d14d9f922 100644 --- a/config/default/manager_image_patch.yaml +++ b/config/default/manager_image_patch.yaml @@ -8,5 +8,5 @@ spec: spec: containers: # Change the value of image field below to your controller image URL - - image: gcr.io/k8s-staging-cluster-api/capk-manager:dev + - image: controller name: manager diff --git a/config/kubevirtci/kustomization.yaml b/config/kubevirtci/kustomization.yaml index d9bbb1f63..035dc18e8 100644 --- a/config/kubevirtci/kustomization.yaml +++ b/config/kubevirtci/kustomization.yaml @@ -3,7 +3,12 @@ namespace: capk-system namePrefix: capk- commonLabels: - cluster.x-k8s.io/provider: "infrastructure-kubevirt" + cluster.x-k8s.io/provider: "kubevirt" + cluster.x-k8s.io/v1alpha1: v1alpha1 + cluster.x-k8s.io/v1alpha2: v1alpha1 + cluster.x-k8s.io/v1alpha3: v1alpha1 + cluster.x-k8s.io/v1alpha4: v1alpha1 + cluster.x-k8s.io/v1beta1: v1alpha1 resources: - namespace.yaml diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 5c5f0b84c..2e6cc7976 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -1,2 +1,2 @@ resources: -- manager.yaml +- manager.yaml \ No newline at end of file diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index d386ac807..f4bd1a581 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -84,8 +84,11 @@ rules: resources: - virtualmachineinstances verbs: + - delete - get - list + - patch + - update - watch - apiGroups: - kubevirt.io diff --git a/controllers/kubevirtcluster_controller.go b/controllers/kubevirtcluster_controller.go index 0adf06384..0ce3a1ea2 100644 --- a/controllers/kubevirtcluster_controller.go +++ b/controllers/kubevirtcluster_controller.go @@ -25,6 +25,7 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + utilerrors "k8s.io/apimachinery/pkg/util/errors" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/annotations" @@ -84,8 +85,6 @@ func (r *KubevirtClusterReconciler) Reconcile(goctx gocontext.Context, req ctrl. return ctrl.Result{}, nil } - log = log.WithValues("cluster", cluster.Name) - // Create the cluster context for this request. clusterContext := &context.ClusterContext{ Context: goctx, @@ -117,9 +116,11 @@ func (r *KubevirtClusterReconciler) Reconcile(goctx gocontext.Context, req ctrl. // Always attempt to Patch the KubevirtCluster object and status after each reconciliation. defer func() { if err := clusterContext.PatchKubevirtCluster(patchHelper); err != nil { - clusterContext.Logger.Error(err, "failed to patch KubevirtCluster") - if rerr == nil { - rerr = err + if !apierrors.IsNotFound(utilerrors.Reduce(err)) { + clusterContext.Logger.Error(err, "failed to patch KubevirtCluster") + if rerr == nil { + rerr = err + } } } }() diff --git a/controllers/kubevirtcluster_controller_test.go b/controllers/kubevirtcluster_controller_test.go index d9ba1c969..11b5066fd 100644 --- a/controllers/kubevirtcluster_controller_test.go +++ b/controllers/kubevirtcluster_controller_test.go @@ -7,10 +7,7 @@ import ( "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - kubevirtv1 "kubevirt.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" . "sigs.k8s.io/controller-runtime" ctrl "sigs.k8s.io/controller-runtime" @@ -44,7 +41,7 @@ var _ = Describe("Reconcile", func() { }) setupClient := func(objects []client.Object) { - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() kubevirtClusterReconciler = controllers.KubevirtClusterReconciler{ Client: fakeClient, InfraCluster: infraClusterMock, @@ -62,7 +59,7 @@ var _ = Describe("Reconcile", func() { cluster, kubevirtCluster, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() }) AfterEach(func() {}) @@ -153,7 +150,7 @@ var _ = Describe("Reconcile", func() { AfterEach(func() {}) - It("should throw an error when reconciling deleted clusters.", func() { + It("should succeed with the kubevirt cluster being deleted.", func() { objects := []client.Object{ cluster, kubevirtCluster, @@ -161,31 +158,21 @@ var _ = Describe("Reconcile", func() { setupClient(objects) infraClusterMock.EXPECT().GenerateInfraClusterClient(gomock.Any(), gomock.Any(), gomock.Any()).Return(fakeClient, kubevirtCluster.Namespace, nil) - _, err := kubevirtClusterReconciler.Reconcile(fakeContext, Request{ - NamespacedName: client.ObjectKey{ - Namespace: kubevirtCluster.Namespace, - Name: kubevirtCluster.Name, - }, + namespacedName := client.ObjectKey{ + Namespace: kubevirtCluster.Namespace, + Name: kubevirtCluster.Name, + } + + result, err := kubevirtClusterReconciler.Reconcile(fakeContext, Request{ + NamespacedName: namespacedName, }) - //test-kubevirt-cluster not found. + Expect(err).ShouldNot(HaveOccurred()) + Expect(result.RequeueAfter).To(BeZero()) + Expect(result.Requeue).To(BeFalse()) + + kvc := &infrav1.KubevirtCluster{} + err = fakeClient.Get(fakeContext, namespacedName, kvc) Expect(err).Should(HaveOccurred()) }) }) }) - -func setupScheme() *runtime.Scheme { - s := runtime.NewScheme() - if err := clusterv1.AddToScheme(s); err != nil { - panic(err) - } - if err := infrav1.AddToScheme(s); err != nil { - panic(err) - } - if err := kubevirtv1.AddToScheme(s); err != nil { - panic(err) - } - if err := corev1.AddToScheme(s); err != nil { - panic(err) - } - return s -} diff --git a/controllers/kubevirtmachine_controller.go b/controllers/kubevirtmachine_controller.go index 8315d45ff..daefad937 100644 --- a/controllers/kubevirtmachine_controller.go +++ b/controllers/kubevirtmachine_controller.go @@ -18,16 +18,17 @@ package controllers import ( gocontext "context" - "encoding/base64" "fmt" "regexp" "time" "github.com/pkg/errors" + "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + utilerrors "k8s.io/apimachinery/pkg/util/errors" kubevirtv1 "kubevirt.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" capierrors "sigs.k8s.io/cluster-api/errors" @@ -424,6 +425,7 @@ func (r *KubevirtMachineReconciler) reconcileDelete(ctx *context.MachineContext) if err != nil { return ctrl.Result{RequeueAfter: 10 * time.Second}, errors.Wrap(err, "failed to create helper for externalMachine access") } + if externalMachine.Exists() { if err := externalMachine.Delete(); err != nil { return ctrl.Result{RequeueAfter: 10 * time.Second}, errors.Wrap(err, "failed to delete VM") @@ -433,11 +435,13 @@ func (r *KubevirtMachineReconciler) reconcileDelete(ctx *context.MachineContext) // Machine is deleted so remove the finalizer. controllerutil.RemoveFinalizer(ctx.KubevirtMachine, infrav1.MachineFinalizer) - // Set the VMProvisionedCondition reporting delete is started, and issue a patch in order to make - // this visible to the users. + // Set the VMProvisionedCondition reporting delete is started, and attempt to issue a patch in + // order to make this visible to the users. conditions.MarkFalse(ctx.KubevirtMachine, infrav1.VMProvisionedCondition, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, "") if err := ctx.PatchKubevirtMachine(patchHelper); err != nil { - return ctrl.Result{}, errors.Wrap(err, "failed to patch KubevirtMachine") + if !apierrors.IsNotFound(utilerrors.Reduce(err)) { + return ctrl.Result{}, errors.Wrap(err, "failed to patch KubevirtMachine") + } } return ctrl.Result{}, nil @@ -583,15 +587,21 @@ func (r *KubevirtMachineReconciler) reconcileKubevirtBootstrapSecret(ctx *contex return errors.New("error retrieving bootstrap data: secret value key is missing") } - if sshKeys != nil && isCloudConfigUserData(value) { - ctx.Logger.Info("Adding users and ssh config to bootstrap userdata...") - value = []byte(string(value) + usersCloudConfig(sshKeys.PublicKey)) + if sshKeys != nil { + var err error + var modified bool + if value, modified, err = addCapkUserToCloudInitConfig(value, sshKeys.PublicKey); err != nil { + return errors.Wrapf(err, "failed to add capk user to KubevirtMachine %s/%s userdata", ctx.Machine.GetNamespace(), ctx.Machine.GetName()) + } else if modified { + ctx.Logger.Info("Add capk user with ssh config to bootstrap userdata") + } } newBootstrapDataSecret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: s.Name + "-userdata", Namespace: vmNamespace, + Labels: s.Labels, }, } ctx.BootstrapDataSecret = newBootstrapDataSecret @@ -634,20 +644,102 @@ func (r *KubevirtMachineReconciler) deleteKubevirtBootstrapSecret(ctx *context.M return nil } -func isCloudConfigUserData(userData []byte) bool { - return regexp.MustCompile(`(?m)^#cloud-config`).MatchString(string(userData)) +// addCapkUserToCloudInitConfig adds the 'capk' user with the provided ssh authorized key to the +// machine cloud-init bootstrap user-data. +// If the user-data is not the expected cloud-init config, then returns the latter content as-is. +// If a capk user is already defined, then overrides it. +// The returned boolean indicates whether the userdata was modified or not. +func addCapkUserToCloudInitConfig(userdata, sshAuthorizedKey []byte) ([]byte, bool, error) { + + // This uses yaml.Node and not an interface{} to preserve the comments, ordering, etc. of the + // cloud-init user-data (the indentation might be modified and aligned). + // Note that go yaml nodes are not a direct representation of the logic structure of the content; + // e.g. + // - the 'users' key and the list (aka sequence) of actual users are sibling nodes + // - the 'name' key and the name value (like 'capk') are sibling nodes + + root := &yaml.Node{} + if err := yaml.Unmarshal(userdata, root); err != nil { + return nil, false, fmt.Errorf("failed to parse userdata yaml: %w", err) + } + + if root.Kind != yaml.DocumentNode || len(root.Content) != 1 { + return userdata, false, nil + } + data := root.Content[0] + if data.Kind != yaml.MappingNode || len(data.Content) == 0 { + return userdata, false, nil + } + + // This resolves the first comment in the document; which can be associated with different nodes + // based on how it is written. + var headerComment string + for _, headerComment = range []string{root.HeadComment, data.HeadComment, data.Content[0].HeadComment} { + if headerComment != "" { + break + } + } + if !regexp.MustCompile(`(?m)^#cloud-config`).MatchString(headerComment) { + return userdata, false, nil + } + + var users *yaml.Node + for i, section := range data.Content { + if i%2 == 1 && section.Kind == yaml.SequenceNode && data.Content[i-1].Value == "users" { + users = section + break + } + } + + usersKey, usersWithCapk, err := usersYamlNodes(sshAuthorizedKey) + if err != nil { + return nil, false, err + } + + // If the users section is not defined in the user-data, simply adds the one with the capk user. + // Otherwise, loops through the users and, either, override the existing capk user or append it + // to the sequence. + if users == nil { + data.Content = append(data.Content, usersKey, usersWithCapk) + } else { + + for i, user := range users.Content { + for j, field := range user.Content { + if j%2 == 1 && user.Content[j-1].Value == "name" { + if field.Value == "capk" { + users.Content[i] = usersWithCapk.Content[0] + ud, err := yaml.Marshal(root) + return ud, true, err + } + break + } + } + } + + users.Content = append(users.Content, usersWithCapk.Content...) + } + + ud, err := yaml.Marshal(root) + return ud, true, err } -// usersCloudConfig generates 'users' cloud config for capk user with a given ssh public key -func usersCloudConfig(sshPublicKey []byte) string { - sshPublicKeyString := base64.StdEncoding.EncodeToString(sshPublicKey) - sshPublicKeyDecoded, _ := base64.StdEncoding.DecodeString(sshPublicKeyString) - - return `users: - - name: capk - gecos: CAPK User - sudo: ALL=(ALL) NOPASSWD:ALL - groups: users, admin - ssh_authorized_keys: - - ` + string(sshPublicKeyDecoded) +// usersYamlNodes generates the yaml.Nodes representing the 'users' key and the sequence of users +// with the capk user and the specified ssh authorized key. +func usersYamlNodes(sshAuthorizedKey []byte) (*yaml.Node, *yaml.Node, error) { + usersYaml := + `users: +- name: capk + gecos: CAPK User + sudo: ALL=(ALL) NOPASSWD:ALL + groups: users, admin + ssh_authorized_keys: + - ` + string(sshAuthorizedKey) + + var node yaml.Node + if err := yaml.Unmarshal([]byte(usersYaml), &node); err != nil { + return nil, nil, fmt.Errorf("failed to render capk user as valid yaml: %w", err) + } + + data := node.Content[0].Content + return data[0], data[1], nil } diff --git a/controllers/kubevirtmachine_controller_test.go b/controllers/kubevirtmachine_controller_test.go index bdbe3a31a..d66da2271 100644 --- a/controllers/kubevirtmachine_controller_test.go +++ b/controllers/kubevirtmachine_controller_test.go @@ -25,13 +25,12 @@ import ( . "github.com/onsi/gomega" "github.com/pkg/errors" - "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/kubevirt" - corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" kubevirtv1 "kubevirt.io/api/core/v1" + "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/kubevirt" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util/conditions" @@ -109,7 +108,7 @@ var _ = Describe("KubevirtClusterToKubevirtMachines", func() { // add one more machine without corresponding kubevirt machine, to test that no request is created for it testing.NewMachine(clusterName, "machine-without-corresponding-kubevirt-machine", nil), } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() kubevirtMachineReconciler = KubevirtMachineReconciler{ Client: fakeClient, MachineFactory: kubevirt.DefaultMachineFactory{}, @@ -136,12 +135,89 @@ var _ = Describe("KubevirtClusterToKubevirtMachines", func() { }) var _ = Describe("utility functions", func() { - DescribeTable("should detect userdata is cloud-config", func(userData []byte, expected bool) { - Expect(isCloudConfigUserData(userData)).To(Equal(expected)) - }, - Entry("should detect cloud-config", []byte("#something\n\n#something else\n#cloud-config\nthe end"), true), - Entry("should not detect cloud-config", []byte("#something\n\n#something else\n#not-cloud-config\nthe end"), false), - Entry("should not detect cloud-config", []byte("#something\n\n#something else\n #cloud-config\nthe end"), false), + + DescribeTable("capk user", + func(userData []byte, sshAuthorizedKey string, expectedOrNil []byte) { + actual, modified, err := addCapkUserToCloudInitConfig(userData, []byte(sshAuthorizedKey)) + Expect(err).ShouldNot(HaveOccurred()) + if expectedOrNil == nil { + Expect(modified).To(BeFalse()) + Expect(string(actual)).To(Equal(string(userData))) + } else { + Expect(modified).To(BeTrue()) + Expect(string(actual)).To(Equal(string(expectedOrNil))) + } + }, + Entry( + "should be added to cloud-init config", + []byte(`## template: jinja +#cloud-config + +write_files: +- path: /etc/kubernetes/pki/ca.crt + owner: root:root + permissions: '0640' + +- path: /run/cluster-api/placeholder + owner: root:root + permissions: '0640' + content: "This placeholder file is used ..." +users: + - name: johndoe + group: users +runcmd: + - 'kubeadm init --config /run/kubeadm/kubeadm.yaml && echo success > /run/cluster-api/bootstrap-success.complete' +`), + "sha-rsa 5678", + []byte(`## template: jinja +#cloud-config + +write_files: + - path: /etc/kubernetes/pki/ca.crt + owner: root:root + permissions: '0640' + - path: /run/cluster-api/placeholder + owner: root:root + permissions: '0640' + content: "This placeholder file is used ..." +users: + - name: johndoe + group: users + - name: capk + gecos: CAPK User + sudo: ALL=(ALL) NOPASSWD:ALL + groups: users, admin + ssh_authorized_keys: + - sha-rsa 5678 +runcmd: + - 'kubeadm init --config /run/kubeadm/kubeadm.yaml && echo success > /run/cluster-api/bootstrap-success.complete' +`), + ), + Entry( + "should be overridden when already in cloud-init config", + []byte(`## template: jinja +#cloud-config +users: + - name: capk + group: users +runcmd: + - 'kubeadm init --config /run/kubeadm/kubeadm.yaml && echo success > /run/cluster-api/bootstrap-success.complete' +`), + "sha-rsa 5678", + []byte(`## template: jinja +#cloud-config +users: + - name: capk + gecos: CAPK User + sudo: ALL=(ALL) NOPASSWD:ALL + groups: users, admin + ssh_authorized_keys: + - sha-rsa 5678 +runcmd: + - 'kubeadm init --config /run/kubeadm/kubeadm.yaml && echo success > /run/cluster-api/bootstrap-success.complete' +`), + ), + Entry("should not be added to non cloud-init config", []byte("hello: world"), "sha-rsa 5678", nil), ) }) @@ -171,8 +247,6 @@ var _ = Describe("reconcile a kubevirt machine", func() { kubevirtMachine = testing.NewKubevirtMachine(kubevirtMachineName, machineName) kubevirtCluster = testing.NewKubevirtCluster(clusterName, machineName) - workloadClusterMock = workloadclustermock.NewMockWorkloadCluster(mockCtrl) - infraClusterMock = infraclustermock.NewMockInfraCluster(mockCtrl) machineFactoryMock = machinemocks.NewMockMachineFactory(mockCtrl) machineMock = machinemocks.NewMockMachineInterface(mockCtrl) @@ -189,7 +263,8 @@ var _ = Describe("reconcile a kubevirt machine", func() { sshKeySecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: sshKeySecretName, + Name: sshKeySecretName, + Labels: map[string]string{"hello": "world"}, }, Data: map[string][]byte{ "pub": []byte("sha-rsa 1234"), @@ -199,7 +274,8 @@ var _ = Describe("reconcile a kubevirt machine", func() { bootstrapSecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: bootstrapSecretName, + Name: bootstrapSecretName, + Labels: map[string]string{"hello": "world"}, }, Data: map[string][]byte{ "value": []byte("shell-script"), @@ -247,7 +323,7 @@ var _ = Describe("reconcile a kubevirt machine", func() { Logger: testLogger, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() kubevirtMachineReconciler = KubevirtMachineReconciler{ Client: fakeClient, WorkloadCluster: workloadClusterMock, @@ -266,7 +342,6 @@ var _ = Describe("reconcile a kubevirt machine", func() { kubevirtMachine, sshKeySecret, bootstrapSecret, - bootstrapUserDataSecret, } setupClient(kubevirt.DefaultMachineFactory{}, objects) @@ -289,6 +364,16 @@ var _ = Describe("reconcile a kubevirt machine", func() { // Should expect kubevirt machine is still not ready Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse()) Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil()) + + // Should have created the userdata secret + machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName + machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: machineContext.Machine.GetNamespace(), Name: *machineBootstrapSecretReferenceName + "-userdata"} + bootstrapDataSecret := &corev1.Secret{} + err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret) + Expect(err).NotTo(HaveOccurred()) + Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script"))) + Expect(bootstrapDataSecret.Labels).To(HaveLen(1)) + Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world")) }) It("should ensure deletion of KubevirtMachine garbage collects everything successfully", func() { @@ -332,11 +417,10 @@ var _ = Describe("reconcile a kubevirt machine", func() { Expect(err).NotTo(HaveOccurred()) bootstrapDataSecret := &corev1.Secret{} err = infraClusterClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret) - expectedErrorMessage := "secrets \"" + *machineBootstrapSecretReferenceName + "-userdata" + "\" not found" - Expect(err.Error()).To(Equal(expectedErrorMessage)) + Expect(apierrors.IsNotFound(err)).To(BeTrue()) //Check finalizer is removed from machine - Expect(len(machineContext.Machine.ObjectMeta.Finalizers)).To(Equal(0)) + Expect(machineContext.Machine.ObjectMeta.Finalizers).To(BeEmpty()) }) It("should ensure deletion of KubevirtMachine when bootstrap secret was never created", func() { @@ -359,7 +443,7 @@ var _ = Describe("reconcile a kubevirt machine", func() { Expect(out).To(Equal(ctrl.Result{Requeue: false, RequeueAfter: 0})) //Check finalizer is removed from machine - Expect(len(machineContext.Machine.ObjectMeta.Finalizers)).To(Equal(0)) + Expect(machineContext.Machine.ObjectMeta.Finalizers).To(BeEmpty()) }) It("should update userdata correctly at KubevirtMachine reconcile", func() { @@ -449,7 +533,6 @@ var _ = Describe("reconcile a kubevirt machine", func() { machine, kubevirtMachine, bootstrapSecret, - bootstrapUserDataSecret, } setupClient(kubevirt.DefaultMachineFactory{}, objects) @@ -472,6 +555,16 @@ var _ = Describe("reconcile a kubevirt machine", func() { // Should expect kubevirt machine is still not ready Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse()) Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil()) + + // Should have created the userdata secret + machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName + machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: kubevirtMachine.Namespace, Name: *machineBootstrapSecretReferenceName + "-userdata"} + bootstrapDataSecret := &corev1.Secret{} + err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret) + Expect(err).NotTo(HaveOccurred()) + Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script"))) + Expect(bootstrapDataSecret.Labels).To(HaveLen(1)) + Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world")) }) It("should create KubeVirt VM in custom namespace", func() { @@ -486,7 +579,6 @@ var _ = Describe("reconcile a kubevirt machine", func() { kubevirtMachine, sshKeySecret, bootstrapSecret, - bootstrapUserDataSecret, } setupClient(kubevirt.DefaultMachineFactory{}, objects) @@ -509,6 +601,16 @@ var _ = Describe("reconcile a kubevirt machine", func() { // Should expect kubevirt machine is still not ready Expect(machineContext.KubevirtMachine.Status.Ready).To(BeFalse()) Expect(machineContext.KubevirtMachine.Spec.ProviderID).To(BeNil()) + + // Should have created the userdata secret + machineBootstrapSecretReferenceName := machineContext.Machine.Spec.Bootstrap.DataSecretName + machineBootstrapSecretReferenceKey := client.ObjectKey{Namespace: customNamespace, Name: *machineBootstrapSecretReferenceName + "-userdata"} + bootstrapDataSecret := &corev1.Secret{} + err = fakeClient.Get(gocontext.Background(), machineBootstrapSecretReferenceKey, bootstrapDataSecret) + Expect(err).NotTo(HaveOccurred()) + Expect(bootstrapDataSecret.Data).To(HaveKeyWithValue("userdata", []byte("shell-script"))) + Expect(bootstrapDataSecret.Labels).To(HaveLen(1)) + Expect(bootstrapDataSecret.Labels).To(HaveKeyWithValue("hello", "world")) }) It("should detect when VMI is ready and mark KubevirtMachine ready", func() { @@ -766,7 +868,7 @@ var _ = Describe("reconcile a kubevirt machine", func() { infraClusterMock.EXPECT().GenerateInfraClusterClient(kubevirtMachine.Spec.InfraClusterSecretRef, kubevirtMachine.Namespace, machineContext.Context).Return(fakeClient, kubevirtMachine.Namespace, nil) _, err := kubevirtMachineReconciler.reconcileNormal(machineContext) - Expect(err).ShouldNot(BeNil()) + Expect(err).Should(HaveOccurred()) conditions := machineContext.KubevirtMachine.GetConditions() Expect(conditions[0].Type).To(Equal(infrav1.VMProvisionedCondition)) @@ -987,7 +1089,7 @@ var _ = Describe("updateNodeProviderID", func() { objects := []client.Object{ kubevirtMachine, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() kubevirtMachineReconciler = KubevirtMachineReconciler{ Client: fakeClient, WorkloadCluster: workloadClusterMock, @@ -1005,7 +1107,7 @@ var _ = Describe("updateNodeProviderID", func() { }, }, } - fakeWorkloadClusterClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(workloadClusterObjects...).Build() + fakeWorkloadClusterClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(workloadClusterObjects...).Build() }) AfterEach(func() {}) @@ -1055,20 +1157,3 @@ var _ = Describe("updateNodeProviderID", func() { Expect(kubevirtMachine.Status.NodeUpdated).To(Equal(false)) }) }) - -func setupScheme() *runtime.Scheme { - s := runtime.NewScheme() - if err := clusterv1.AddToScheme(s); err != nil { - panic(err) - } - if err := infrav1.AddToScheme(s); err != nil { - panic(err) - } - if err := kubevirtv1.AddToScheme(s); err != nil { - panic(err) - } - if err := corev1.AddToScheme(s); err != nil { - panic(err) - } - return s -} diff --git a/controllers/vmi_eviction_controller.go b/controllers/vmi_eviction_controller.go new file mode 100644 index 000000000..3f91eb0b5 --- /dev/null +++ b/controllers/vmi_eviction_controller.go @@ -0,0 +1,276 @@ +package controllers + +import ( + goContext "context" + "fmt" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/predicate" + "time" + + "github.com/go-logr/logr" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kubedrain "k8s.io/kubectl/pkg/drain" + kubevirtv1 "kubevirt.io/api/core/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/controllers/noderefutil" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + infrav1 "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" + context "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/context" + "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/workloadcluster" +) + +const ( + vmiDeleteGraceTimeoutDurationSeconds = 600 // 10 minutes +) + +type VmiEvictionReconciler struct { + client.Client + workloadCluster workloadcluster.WorkloadCluster +} + +// NewVmiEvictionReconciler creates a new VmiEvictionReconciler +func NewVmiEvictionReconciler(cl client.Client) *VmiEvictionReconciler { + return &VmiEvictionReconciler{Client: cl, workloadCluster: workloadcluster.New(cl)} +} + +// SetupWithManager will add watches for this controller. +func (r *VmiEvictionReconciler) SetupWithManager(ctx goContext.Context, mgr ctrl.Manager) error { + selector, err := getLabelPredicate() + + if err != nil { + return fmt.Errorf("can't setup the VMI eviction controller; %w", err) + } + + _, err = ctrl.NewControllerManagedBy(mgr). + For(&kubevirtv1.VirtualMachineInstance{}). + WithEventFilter(selector). + Build(r) + + return err +} + +// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters;machines,verbs=get;list;watch +// +kubebuilder:rbac:groups="",resources=secrets;,verbs=get;list;watch +// +kubebuilder:rbac:groups=kubevirt.io,resources=virtualmachineinstances;,verbs=get;list;watch;patch;update;delete + +// Reconcile handles VMI events. +func (r VmiEvictionReconciler) Reconcile(ctx goContext.Context, req ctrl.Request) (ctrl.Result, error) { + logger := ctrl.LoggerFrom(ctx) + + vmi := &kubevirtv1.VirtualMachineInstance{} + err := r.Get(ctx, req.NamespacedName, vmi) + if err != nil { + if apierrors.IsNotFound(err) { + logger.V(4).Info(fmt.Sprintf("Can't find virtualMachineInstance %s; it was already deleted.", req.NamespacedName)) + return ctrl.Result{}, nil + } + logger.Error(err, fmt.Sprintf("failed to read VMI %s", req.Name)) + return ctrl.Result{}, err + } + + if !shouldGracefulDeleteVMI(vmi, logger, req.NamespacedName) { + return ctrl.Result{}, nil + } + + exceeded, err := r.drainGracePeriodExceeded(ctx, vmi, logger) + if err != nil { + return ctrl.Result{}, err + } + + if !exceeded { + cluster, err := r.getCluster(ctx, vmi) + if err != nil { + logger.Error(err, "Can't get the cluster form the VirtualMachineInstance", "VirtualMachineInstance name", req.NamespacedName) + return ctrl.Result{}, err + } + + nodeDrained, retryDuration, err := r.drainNode(ctx, cluster, vmi.Status.EvacuationNodeName, logger) + if err != nil { + return ctrl.Result{RequeueAfter: retryDuration}, err + } + + if !nodeDrained { + return ctrl.Result{RequeueAfter: retryDuration}, nil + } + } + + // now, when the node is drained (or vmiDeleteGraceTimeoutDurationSeconds has passed), we can delete the VMI + propagationPolicy := metav1.DeletePropagationForeground + err = r.Delete(ctx, vmi, &client.DeleteOptions{PropagationPolicy: &propagationPolicy}) + if err != nil { + logger.Error(err, "failed to delete VirtualMachineInstance", "VirtualMachineInstance name", req.NamespacedName) + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +func shouldGracefulDeleteVMI(vmi *kubevirtv1.VirtualMachineInstance, logger logr.Logger, namespacedName types.NamespacedName) bool { + if vmi.DeletionTimestamp != nil { + logger.V(4).Info("The virtualMachineInstance is already in deletion process. Nothing to do here", "VirtualMachineInstance name", namespacedName) + return false + } + + if vmi.Spec.EvictionStrategy == nil || *vmi.Spec.EvictionStrategy != kubevirtv1.EvictionStrategyExternal { + logger.V(4).Info("Graceful deletion is not supported for virtualMachineInstance. Nothing to do here", "VirtualMachineInstance name", namespacedName) + return false + } + + // KubeVirt will set the EvacuationNodeName field in case of guest node eviction. If the field is not set, there is + // nothing to do. + if len(vmi.Status.EvacuationNodeName) == 0 { + logger.V(4).Info("The virtualMachineInstance is not marked for deletion. Nothing to do here", "VirtualMachineInstance name", namespacedName) + return false + } + + return true +} + +func (r VmiEvictionReconciler) getCluster(ctx goContext.Context, vmi *kubevirtv1.VirtualMachineInstance) (*clusterv1.Cluster, error) { + // get cluster from vmi + clusterNS, ok := vmi.Labels[infrav1.KubevirtMachineNamespaceLabel] + if !ok { + return nil, fmt.Errorf("can't find the cluster namespace from the VM; missing %s label", infrav1.KubevirtMachineNamespaceLabel) + } + + clusterName, ok := vmi.Labels[clusterv1.ClusterLabelName] + if !ok { + return nil, fmt.Errorf("can't find the cluster name from the VM; missing %s label", clusterv1.ClusterLabelName) + } + + cluster := &clusterv1.Cluster{} + err := r.Get(ctx, client.ObjectKey{Namespace: clusterNS, Name: clusterName}, cluster) + if err != nil { + return nil, fmt.Errorf("can't find the cluster %s/%s; %w", clusterNS, clusterName, err) + } + + return cluster, nil +} + +// This functions drains a node from a tenant cluster. +// The function returns 3 values: +// * drain done - boolean +// * retry time, or 0 if not needed +// * error - to be returned if we want to retry +func (r VmiEvictionReconciler) drainNode(goctx goContext.Context, cluster *clusterv1.Cluster, nodeName string, logger logr.Logger) (bool, time.Duration, error) { + ctx := &context.MachineContext{Context: goctx, KubevirtCluster: &infrav1.KubevirtCluster{ObjectMeta: metav1.ObjectMeta{Namespace: cluster.Namespace, Name: cluster.Name}}} + kubeClient, err := r.workloadCluster.GenerateWorkloadClusterK8sClient(ctx) + if err != nil { + logger.Error(err, "Error creating a remote client while deleting Machine, won't retry") + return false, 0, nil + } + + node, err := kubeClient.CoreV1().Nodes().Get(goctx, nodeName, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + // If an admin deletes the node directly, we'll end up here. + logger.Error(err, "Could not find node from noderef, it may have already been deleted") + return true, 0, nil + } + return false, 0, fmt.Errorf("unable to get node %q: %w", nodeName, err) + } + + drainer := &kubedrain.Helper{ + Client: kubeClient, + Ctx: ctx, + Force: true, + IgnoreAllDaemonSets: true, + DeleteEmptyDirData: true, + GracePeriodSeconds: -1, + // If a pod is not evicted in 20 seconds, retry the eviction next time the + // machine gets reconciled again (to allow other machines to be reconciled). + Timeout: 20 * time.Second, + OnPodDeletedOrEvicted: func(pod *corev1.Pod, usingEviction bool) { + verbStr := "Deleted" + if usingEviction { + verbStr = "Evicted" + } + logger.Info(fmt.Sprintf("%s pod from Node", verbStr), + "pod", fmt.Sprintf("%s/%s", pod.Name, pod.Namespace)) + }, + Out: writer{logger.Info}, + ErrOut: writer{func(msg string, keysAndValues ...interface{}) { + logger.Error(nil, msg, keysAndValues...) + }}, + } + + if noderefutil.IsNodeUnreachable(node) { + // When the node is unreachable and some pods are not evicted for as long as this timeout, we ignore them. + drainer.SkipWaitForDeleteTimeoutSeconds = 60 * 5 // 5 minutes + } + + if err = kubedrain.RunCordonOrUncordon(drainer, node, true); err != nil { + // Machine will be re-reconciled after a cordon failure. + logger.Error(err, "Cordon failed") + return false, 0, errors.Errorf("unable to cordon node %s: %v", nodeName, err) + } + + if err = kubedrain.RunNodeDrain(drainer, node.Name); err != nil { + // Machine will be re-reconciled after a drain failure. + logger.Error(err, "Drain failed, retry in 20s", "node name", nodeName) + return false, 20 * time.Second, nil + } + + logger.Info("Drain successful", "node name", nodeName) + return true, 0, nil +} + +// wait vmiDeleteGraceTimeoutDurationSeconds to the node to be drained. If this time had passed, don't wait anymore. +func (r VmiEvictionReconciler) drainGracePeriodExceeded(ctx goContext.Context, vmi *kubevirtv1.VirtualMachineInstance, logger logr.Logger) (bool, error) { + if graceTime, found := vmi.Annotations[infrav1.VmiDeletionGraceTime]; found { + deletionGraceTime, err := time.Parse(time.RFC3339, graceTime) + if err != nil { // wrong format - rewrite + if err = r.setVmiDeletionGraceTime(ctx, vmi, logger); err != nil { + return false, err + } + } else { + return time.Now().UTC().After(deletionGraceTime), nil + } + } else { + if err := r.setVmiDeletionGraceTime(ctx, vmi, logger); err != nil { + return false, err + } + } + + return false, nil +} + +func (r VmiEvictionReconciler) setVmiDeletionGraceTime(ctx goContext.Context, vmi *kubevirtv1.VirtualMachineInstance, logger logr.Logger) error { + logger.V(2).Info(fmt.Sprintf("setting the %s annotation", infrav1.VmiDeletionGraceTime)) + graceTime := time.Now().Add(vmiDeleteGraceTimeoutDurationSeconds * time.Second).UTC().Format(time.RFC3339) + patch := fmt.Sprintf(`{"metadata":{"annotations":{"%s": "%s"}}}`, infrav1.VmiDeletionGraceTime, graceTime) + patchRequest := client.RawPatch(types.MergePatchType, []byte(patch)) + + if err := r.Patch(ctx, vmi, patchRequest); err != nil { + return fmt.Errorf("failed to add the %s annotation to the VMI; %w", infrav1.VmiDeletionGraceTime, err) + } + + return nil +} + +func getLabelPredicate() (predicate.Predicate, error) { + return predicate.LabelSelectorPredicate( + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{{ + Key: infrav1.KubevirtMachineNameLabel, + Operator: metav1.LabelSelectorOpExists, + Values: nil, + }}, + }) +} + +// writer implements io.Writer interface as a pass-through for klog. +type writer struct { + logFunc func(msg string, keysAndValues ...interface{}) +} + +// Write passes string(p) into writer's logFunc and always returns len(p). +func (w writer) Write(p []byte) (n int, err error) { + w.logFunc(string(p)) + return len(p), nil +} diff --git a/controllers/vmi_eviction_controller_test.go b/controllers/vmi_eviction_controller_test.go new file mode 100644 index 000000000..5e78f82c7 --- /dev/null +++ b/controllers/vmi_eviction_controller_test.go @@ -0,0 +1,465 @@ +package controllers + +import ( + gocontext "context" + "errors" + "time" + + "github.com/golang/mock/gomock" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + k8sfake "k8s.io/client-go/kubernetes/fake" + kubevirtv1 "kubevirt.io/api/core/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/event" + + infrav1 "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" + "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/testing" + "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/workloadcluster/mock" +) + +var _ = Describe("Test VMI Controller", func() { + + const ( + clusterName = "test" + clusterNamespace = clusterName + "-cluster" + clusterInstanceName = clusterName + "-1234" + nodeName = "worker-node-1" + ) + + Context("Test VmiEviction reconciler", func() { + var ( + mockCtrl *gomock.Controller + fakeClient client.Client + vmi *kubevirtv1.VirtualMachineInstance + cluster *clusterv1.Cluster + wlCluster *mock.MockWorkloadCluster + ) + + BeforeEach(func() { + mockCtrl = gomock.NewController(GinkgoT()) + + vmi = &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-cluster", + Name: nodeName, + Labels: map[string]string{ + infrav1.KubevirtMachineNamespaceLabel: clusterNamespace, + clusterv1.ClusterLabelName: clusterInstanceName, + }, + Annotations: make(map[string]string), + }, + } + + cluster = &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: clusterNamespace, + Name: clusterInstanceName, + }, + Spec: clusterv1.ClusterSpec{ + InfrastructureRef: &corev1.ObjectReference{ + Kind: "Secret", + Namespace: clusterNamespace, + Name: clusterInstanceName, + }, + }, + } + + wlCluster = mock.NewMockWorkloadCluster(mockCtrl) + }) + + It("Should ignore vmi if it already deleted", func() { + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + It("Should ignore vmi if its deletion process already started", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + now := metav1.Now() + vmi.DeletionTimestamp = &now + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + It("Should ignore vmi with no eviction strategy", func() { + vmi.Spec.EvictionStrategy = nil + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + It("Should ignore vmi with no eviction strategy != external", func() { + es := kubevirtv1.EvictionStrategyLiveMigrate + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + It("Should ignore non-evicted VMIs", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + It("Should drain node", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: nodeName, + }, + } + + Expect(k8sfake.AddToScheme(setupRemoteScheme())).ToNot(HaveOccurred()) + cl := k8sfake.NewSimpleClientset(node) + + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Return(cl, nil).Times(1) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + + // check that the node was drained + readNode, err := cl.CoreV1().Nodes().Get(gocontext.TODO(), nodeName, metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + Expect(readNode.Spec.Unschedulable).To(BeTrue()) + + // check that the VMI was removed + readVMI := &kubevirtv1.VirtualMachineInstance{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKey{Namespace: clusterNamespace, Name: nodeName}, readVMI) + Expect(apierrors.IsNotFound(err)).Should(BeTrue()) + }) + + It("Should skip drain if the node already deleted", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + + vmi.Status.EvacuationNodeName = nodeName + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + Expect(k8sfake.AddToScheme(setupRemoteScheme())).ToNot(HaveOccurred()) + cl := k8sfake.NewSimpleClientset() + + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Return(cl, nil).Times(1) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + Expect(r.Reconcile(gocontext.TODO(), req)).Should(Equal(ctrl.Result{})) + }) + + Context("Error cases", func() { + It("Should return error if the 'capk.cluster.x-k8s.io/kubevirt-machine-namespace' label is missing", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + delete(vmi.Labels, infrav1.KubevirtMachineNamespaceLabel) + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + _, err := r.Reconcile(gocontext.TODO(), req) + Expect(err).Should(HaveOccurred()) + }) + + It("Should return error if the 'cluster.x-k8s.io/cluster-name' label is missing", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + delete(vmi.Labels, clusterv1.ClusterLabelName) + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + _, err := r.Reconcile(gocontext.TODO(), req) + Expect(err).Should(HaveOccurred()) + }) + + It("Should return error if the cluster is missing", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi).Build() + + // make sure we never get into darin process, but exit earlier + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Times(0) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + _, err := r.Reconcile(gocontext.TODO(), req) + Expect(err).Should(HaveOccurred()) + }) + + It("Should return not error if can't get the external cluster client, but do not remove the VMI", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + + Expect(k8sfake.AddToScheme(setupRemoteScheme())).ToNot(HaveOccurred()) + + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: nodeName, + }, + } + + Expect(k8sfake.AddToScheme(setupRemoteScheme())).ToNot(HaveOccurred()) + cl := k8sfake.NewSimpleClientset(node) + + wlCluster.EXPECT().GenerateWorkloadClusterK8sClient(gomock.Any()).Return(nil, errors.New("fake error")).Times(1) + + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + req := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "test-cluster", Name: nodeName}} + + _, err := r.Reconcile(gocontext.TODO(), req) + Expect(err).ShouldNot(HaveOccurred()) + + // check that the node was not drained + readNode, err := cl.CoreV1().Nodes().Get(gocontext.TODO(), nodeName, metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + Expect(readNode.Spec.Unschedulable).To(BeFalse()) + + // check that the VMI was not deleted + readVMI := &kubevirtv1.VirtualMachineInstance{} + err = fakeClient.Get(gocontext.TODO(), client.ObjectKey{Namespace: clusterNamespace, Name: nodeName}, readVMI) + Expect(err).ShouldNot(HaveOccurred()) + Expect(readVMI).ToNot(BeNil()) + }) + }) + + Context("test drainGracePeriodExceeded", func() { + It("should add the annotation", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + ctx := gocontext.Background() + Expect(r.drainGracePeriodExceeded(ctx, vmi, ctrl.LoggerFrom(ctx))).To(BeFalse()) + timeoutAnnotation, found := vmi.Annotations[infrav1.VmiDeletionGraceTime] + Expect(found).To(BeTrue()) + timeout, err := time.Parse(time.RFC3339, timeoutAnnotation) + Expect(err).ToNot(HaveOccurred()) + Expect(timeout).To(And( + BeTemporally(">", time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds-1)*time.Second)), + BeTemporally("<", time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds+1)*time.Second)))) + }) + + It("should return false if timeout was not exceeded", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + timeout := time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds / 2) * time.Second).Format(time.RFC3339) + vmi.Annotations[infrav1.VmiDeletionGraceTime] = timeout + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + ctx := gocontext.Background() + Expect(r.drainGracePeriodExceeded(ctx, vmi, ctrl.LoggerFrom(ctx))).To(BeFalse()) + timeoutAnnotation, found := vmi.Annotations[infrav1.VmiDeletionGraceTime] + Expect(found).To(BeTrue()) + Expect(timeoutAnnotation).To(Equal(timeout)) + }) + + It("should return true if timeout was exceeded", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + timeout := time.Now().UTC().Add(-(time.Millisecond)).Format(time.RFC3339) + vmi.Annotations[infrav1.VmiDeletionGraceTime] = timeout + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + ctx := gocontext.Background() + Expect(r.drainGracePeriodExceeded(ctx, vmi, ctrl.LoggerFrom(ctx))).To(BeTrue()) + timeoutAnnotation, found := vmi.Annotations[infrav1.VmiDeletionGraceTime] + Expect(found).To(BeTrue()) + Expect(timeoutAnnotation).To(Equal(timeout)) + }) + + It("should fix the annotation if it's with a wrong format", func() { + es := kubevirtv1.EvictionStrategyExternal + vmi.Spec.EvictionStrategy = &es + vmi.Status.EvacuationNodeName = nodeName + + origTimeout := time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds / 2) * time.Second).Format(time.RFC850) + vmi.Annotations[infrav1.VmiDeletionGraceTime] = origTimeout + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(vmi, cluster).Build() + r := &VmiEvictionReconciler{Client: fakeClient, workloadCluster: wlCluster} + ctx := gocontext.Background() + Expect(r.drainGracePeriodExceeded(ctx, vmi, ctrl.LoggerFrom(ctx))).To(BeFalse()) + timeoutAnnotation, found := vmi.Annotations[infrav1.VmiDeletionGraceTime] + Expect(found).To(BeTrue()) + timeout, err := time.Parse(time.RFC3339, timeoutAnnotation) + Expect(err).ToNot(HaveOccurred()) + Expect(timeout).To(And( + BeTemporally(">", time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds-1)*time.Second)), + BeTemporally("<", time.Now().UTC().Add((vmiDeleteGraceTimeoutDurationSeconds+1)*time.Second)))) + }) + }) + }) + + Context("check the label predicate", func() { + sel, err := getLabelPredicate() + It("should successfully create the predicate", func() { + Expect(err).ToNot(HaveOccurred()) + }) + + It("should select if the label exist", func() { + Expect(sel.Create(event.CreateEvent{ + Object: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: "machine-name"}, + }, + }, + })).To(BeTrue()) + }) + + It("should select if the label exist and empty", func() { + Expect(sel.Create(event.CreateEvent{ + Object: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: ""}, + }, + }, + })).To(BeTrue()) + }) + + It("should select if the label does not exist", func() { + Expect(sel.Create(event.CreateEvent{ + Object: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: nil, + }, + }, + })).To(BeFalse()) + }) + + It("should select if the label exist", func() { + Expect(sel.Update(event.UpdateEvent{ + ObjectOld: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: "machine-name"}, + }, + }, + ObjectNew: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: "machine-name"}, + }, + }, + })).To(BeTrue()) + }) + + It("should select if the label now exist", func() { + Expect(sel.Update(event.UpdateEvent{ + ObjectOld: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"foo": "bar"}, + }, + }, + ObjectNew: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: "machine-name"}, + }, + }, + })).To(BeTrue()) + + }) + + It("should select if the label now not exist", func() { + Expect(sel.Update(event.UpdateEvent{ + ObjectOld: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{infrav1.KubevirtMachineNameLabel: "machine-name"}, + }, + }, + ObjectNew: &kubevirtv1.VirtualMachineInstance{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"foo": "bar"}, + }, + }, + })).To(BeFalse()) + }) + }) + +}) + +func setupRemoteScheme() *runtime.Scheme { + s := runtime.NewScheme() + if err := corev1.AddToScheme(s); err != nil { + panic(err) + } + return s +} diff --git a/docs/our-image-creation-process.md b/docs/our-image-creation-process.md new file mode 100644 index 000000000..e1745c5a3 --- /dev/null +++ b/docs/our-image-creation-process.md @@ -0,0 +1,8 @@ +Our image creation process is based on kubernetes-sigs/image-builder project based on packer. +We added a kubevirt target that creates an ubuntu kubevirt image. + +This is currently(3.may.22) added in this PR: https://github.com/kubernetes-sigs/image-builder/pull/847 + +*Clone this PR +*cd into images/capi +*Run "make build-kubevirt-qemu-ubuntu-2004" \ No newline at end of file diff --git a/e2e/common_test.go b/e2e/common_test.go index f1d5e6e79..e61719e18 100644 --- a/e2e/common_test.go +++ b/e2e/common_test.go @@ -4,12 +4,22 @@ import ( "bytes" "context" "fmt" + "io" + "net" + "os" "os/exec" + "strings" "time" + "github.com/golang/glog" . "github.com/onsi/gomega" + kubevirtv1 "kubevirt.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -45,8 +55,145 @@ func RunCmd(cmd *exec.Cmd) (stdoutBytes []byte, stderrBytes []byte) { cmd.Stderr = stderr // run the command - err := cmd.Run() - Expect(err).To(BeNil()) + ExpectWithOffset(1, cmd.Run()).To(Succeed(), fmt.Sprintf("failed to run %s, with arguments: %v; error response: %s", cmd.Path, cmd.Args, stderr.Bytes())) return stdout.Bytes(), stderr.Bytes() } + +type tenantClusterAccess struct { + listener net.Listener + namespace string + tenantKubeconfigFile string + isForwarding bool +} + +func newTenantClusterAccess(namespace string, tenantKubeconfigFile string) tenantClusterAccess { + return tenantClusterAccess{ + namespace: namespace, + tenantKubeconfigFile: tenantKubeconfigFile, + } +} + +func (t *tenantClusterAccess) generateClient() (*kubernetes.Clientset, error) { + localPort := t.listener.Addr().(*net.TCPAddr).Port + cmd := exec.Command(ClusterctlPath, "get", "kubeconfig", "kvcluster", + "--namespace", t.namespace) + stdout, _ := RunCmd(cmd) + if err := os.WriteFile(t.tenantKubeconfigFile, stdout, 0644); err != nil { + return nil, err + } + clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + &clientcmd.ClientConfigLoadingRules{ExplicitPath: t.tenantKubeconfigFile}, + &clientcmd.ConfigOverrides{ + ClusterInfo: clientcmdapi.Cluster{ + Server: fmt.Sprintf("https://127.0.0.1:%d", localPort), + InsecureSkipTLSVerify: true, + }, + }) + restConfig, err := clientConfig.ClientConfig() + if err != nil { + return nil, err + } + + return kubernetes.NewForConfig(restConfig) +} + +func (t *tenantClusterAccess) getLocalPort() int { + return t.listener.Addr().(*net.TCPAddr).Port +} + +func (t *tenantClusterAccess) startForwardingTenantAPI() error { + if t.isForwarding { + return nil + } + address, err := net.ResolveIPAddr("", "127.0.0.1") + if err != nil { + return err + } + t.listener, err = net.ListenTCP( + "tcp", + &net.TCPAddr{ + IP: address.IP, + Zone: address.Zone, + }) + if err != nil { + return err + } + + vmiName, err := t.findControlPlaneVMIName() + if err != nil { + return err + } + + t.isForwarding = true + go t.waitForConnection(vmiName, t.namespace) + + return nil +} + +func (t *tenantClusterAccess) findControlPlaneVMIName() (string, error) { + vmiList, err := virtClient.VirtualMachineInstance(t.namespace).List(&metav1.ListOptions{}) + if err != nil { + return "", err + } + + var chosenVMI *kubevirtv1.VirtualMachineInstance + for _, vmi := range vmiList.Items { + if strings.Contains(vmi.Name, "-control-plane") { + chosenVMI = &vmi + break + } + } + if chosenVMI == nil { + return "", fmt.Errorf("Couldn't find controlplane vmi in namespace %s", t.namespace) + } + return chosenVMI.Name, nil +} + +func (t *tenantClusterAccess) stopForwardingTenantAPI() error { + if !t.isForwarding { + return nil + } + t.isForwarding = false + return t.listener.Close() +} + +func (t *tenantClusterAccess) waitForConnection(name, namespace string) { + for { + conn, err := t.listener.Accept() + if err != nil { + glog.Errorln("error accepting connection:", err) + return + } + stream, err := virtClient.VirtualMachineInstance(namespace).PortForward(name, 6443, "tcp") + if err != nil { + glog.Errorf("can't access vmi %s/%s: %v", namespace, name, err) + return + } + go t.handleConnection(conn, stream.AsConn()) + } +} + +// handleConnection copies data between the local connection and the stream to +// the remote server. +func (t *tenantClusterAccess) handleConnection(local, remote net.Conn) { + defer local.Close() + defer remote.Close() + errs := make(chan error, 2) + go func() { + _, err := io.Copy(remote, local) + errs <- err + }() + go func() { + _, err := io.Copy(local, remote) + errs <- err + }() + + t.handleConnectionError(<-errs) +} + +func (t *tenantClusterAccess) handleConnectionError(err error) { + if err != nil && !strings.Contains(err.Error(), "use of closed network connection") { + glog.Errorf("error handling portForward connection: %v", err) + } +} diff --git a/e2e/create-cluster_test.go b/e2e/create-cluster_test.go index 0d67bccc3..ebdb21d7c 100644 --- a/e2e/create-cluster_test.go +++ b/e2e/create-cluster_test.go @@ -7,17 +7,24 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strings" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" + policy "k8s.io/api/policy/v1beta1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/client-go/kubernetes" + "k8s.io/utils/pointer" kubevirtv1 "kubevirt.io/api/core/v1" + "kubevirt.io/client-go/kubecli" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/cluster-api/util/conditions" "sigs.k8s.io/controller-runtime/pkg/client" @@ -27,12 +34,20 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" ) +var virtClient kubecli.KubevirtClient + +const testFinalizer = "holdForTestFinalizer" + var _ = Describe("CreateCluster", func() { var tmpDir string var k8sclient client.Client var manifestsFile string + var tenantKubeconfigFile string var namespace string + var tenantAccessor tenantClusterAccess + + calicoManifestsUrl := "https://docs.projectcalico.org/v3.21/manifests/calico.yaml" BeforeEach(func() { var err error @@ -41,11 +56,15 @@ var _ = Describe("CreateCluster", func() { Expect(err).ToNot(HaveOccurred()) manifestsFile = filepath.Join(tmpDir, "manifests.yaml") + tenantKubeconfigFile = filepath.Join(tmpDir, "tenant-kubeconfig.yaml") cfg, err := config.GetConfig() Expect(err).ToNot(HaveOccurred()) k8sclient, err = client.New(cfg, client.Options{}) Expect(err).ToNot(HaveOccurred()) + clientConfig := kubecli.DefaultClientConfig(&pflag.FlagSet{}) + virtClient, err = kubecli.GetKubevirtClientFromClientConfig(clientConfig) + Expect(err).ToNot(HaveOccurred()) _ = clusterv1.AddToScheme(k8sclient.Scheme()) _ = infrav1.AddToScheme(k8sclient.Scheme()) @@ -59,6 +78,7 @@ var _ = Describe("CreateCluster", func() { }, } + tenantAccessor = newTenantClusterAccess(namespace, tenantKubeconfigFile) err = k8sclient.Create(context.Background(), ns) Expect(err).ToNot(HaveOccurred()) }) @@ -79,6 +99,8 @@ var _ = Describe("CreateCluster", func() { _ = os.RemoveAll(tmpDir) + _ = tenantAccessor.stopForwardingTenantAPI() + By("removing cluster") cluster := &clusterv1.Cluster{ ObjectMeta: metav1.ObjectMeta{ @@ -107,22 +129,25 @@ var _ = Describe("CreateCluster", func() { } } return nil - }, 5*time.Minute, 5*time.Second).Should(Succeed(), "kubevirt machines should have bootstrap succeeded condition") + }).WithOffset(1). + WithTimeout(10*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "kubevirt machines should have bootstrap succeeded condition") } markExternalKubeVirtClusterReady := func(clusterName string, namespace string) { By("Ensuring no other controller is managing the kvcluster's status") - Consistently(func() error { + Consistently(func(g Gomega) error { kvCluster := &infrav1.KubevirtCluster{} key := client.ObjectKey{Namespace: namespace, Name: clusterName} err := k8sclient.Get(context.Background(), key, kvCluster) - Expect(err).ToNot(HaveOccurred()) + g.Expect(err).ToNot(HaveOccurred()) - Expect(kvCluster.Finalizers).To(BeEmpty()) - Expect(kvCluster.Status.Ready).To(BeFalse()) - Expect(kvCluster.Status.FailureDomains).To(BeEmpty()) - Expect(kvCluster.Status.Conditions).To(BeEmpty()) + g.Expect(kvCluster.Finalizers).To(BeEmpty()) + g.Expect(kvCluster.Status.Ready).To(BeFalse()) + g.Expect(kvCluster.Status.FailureDomains).To(BeEmpty()) + g.Expect(kvCluster.Status.Conditions).To(BeEmpty()) return nil }, 30*time.Second, 5*time.Second).Should(Succeed()) @@ -223,7 +248,116 @@ var _ = Describe("CreateCluster", func() { } return nil - }, 5*time.Minute, 5*time.Second).Should(Succeed(), "waiting for expected readiness.") + }).WithOffset(1). + WithTimeout(5*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "waiting for expected readiness.") + } + + waitForTenantPods := func() { + + By(fmt.Sprintf("Perform Port Forward using controlplane vmi in namespace %s", namespace)) + err := tenantAccessor.startForwardingTenantAPI() + Expect(err).ToNot(HaveOccurred()) + + By("Create client to access the tenant cluster") + clientSet, err := tenantAccessor.generateClient() + Expect(err).ToNot(HaveOccurred()) + + Eventually(func(g Gomega) error { + podList, err := clientSet.CoreV1().Pods("kube-system").List(context.Background(), metav1.ListOptions{}) + g.Expect(err).ToNot(HaveOccurred()) + + offlinePodList := []string{} + for _, pod := range podList.Items { + if pod.Status.Phase != corev1.PodRunning { + offlinePodList = append(offlinePodList, pod.Name) + } + } + + if len(offlinePodList) > 0 { + + return fmt.Errorf("Waiting on tenant pods [%v] to reach a Running phase", offlinePodList) + } + return nil + }).WithOffset(1). + WithTimeout(8*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "waiting for pods to hit Running phase.") + + } + + waitForTenantAccess := func(numExpectedNodes int) *kubernetes.Clientset { + By(fmt.Sprintf("Perform Port Forward using controlplane vmi in namespace %s", namespace)) + err := tenantAccessor.startForwardingTenantAPI() + Expect(err).ToNot(HaveOccurred()) + + By("Create client to access the tenant cluster") + clientSet, err := tenantAccessor.generateClient() + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() error { + + nodeList, err := clientSet.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + Expect(err).ToNot(HaveOccurred()) + if len(nodeList.Items) != numExpectedNodes { + return fmt.Errorf("expecting tenant cluster to have %d nodes", len(nodeList.Items)) + } + + return nil + }).WithOffset(1). + WithTimeout(5*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "waiting for expected readiness.") + + return clientSet + } + + waitForNodeReadiness := func() *kubernetes.Clientset { + By(fmt.Sprintf("Perform Port Forward using controlplane vmi in namespace %s", namespace)) + err := tenantAccessor.startForwardingTenantAPI() + Expect(err).ToNot(HaveOccurred()) + + By("Create client to access the tenant cluster") + clientSet, err := tenantAccessor.generateClient() + Expect(err).ToNot(HaveOccurred()) + + Eventually(func(g Gomega) error { + + nodeList, err := clientSet.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + g.Expect(err).ToNot(HaveOccurred()) + + for _, node := range nodeList.Items { + + ready := false + networkAvailable := false + for _, cond := range node.Status.Conditions { + if cond.Type == corev1.NodeReady && cond.Status == corev1.ConditionTrue { + ready = true + } else if cond.Type == corev1.NodeNetworkUnavailable && cond.Status == corev1.ConditionFalse { + networkAvailable = true + } + } + + if !ready { + return fmt.Errorf("waiting on node %s to become ready", node.Name) + } else if !networkAvailable { + return fmt.Errorf("waiting on node %s to have network availablity", node.Name) + } + } + + return nil + }).WithOffset(1). + WithTimeout(8*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "ensure healthy nodes.") + + return clientSet + } + + installCalicoCNI := func() { + cmd := exec.Command(KubectlPath, "--kubeconfig", tenantKubeconfigFile, "--insecure-skip-tls-verify", "--server", fmt.Sprintf("https://localhost:%d", tenantAccessor.getLocalPort()), "apply", "-f", calicoManifestsUrl) + RunCmd(cmd) } waitForNodeUpdate := func() { @@ -246,7 +380,7 @@ var _ = Describe("CreateCluster", func() { waitForControlPlane := func() { By("Waiting on cluster's control plane to initialize") - Eventually(func() error { + Eventually(func(g Gomega) error { cluster := &clusterv1.Cluster{} key := client.ObjectKey{Namespace: namespace, Name: "kvcluster"} err := k8sclient.Get(context.Background(), key, cluster) @@ -255,11 +389,14 @@ var _ = Describe("CreateCluster", func() { } if !conditions.IsTrue(cluster, clusterv1.ControlPlaneInitializedCondition) { - return fmt.Errorf("still waiting on controlPlaneInitialized condition to be true") + return fmt.Errorf("still waiting on controlPlaneReady condition to be true") } return nil - }, 10*time.Minute, 5*time.Second).Should(Succeed(), "cluster should have control plane initialized") + }).WithOffset(1). + WithTimeout(20*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "cluster should have control plane initialized") By("Waiting on cluster's control plane to be ready") Eventually(func() error { @@ -275,7 +412,10 @@ var _ = Describe("CreateCluster", func() { } return nil - }, 10*time.Minute, 5*time.Second).Should(Succeed(), "cluster should have control plane initialized") + }).WithOffset(1). + WithTimeout(15*time.Minute). + WithPolling(5*time.Second). + Should(Succeed(), "cluster should have control plane initialized") } injectKubevirtClusterExternallyManagedAnnotation := func(yamlStr string) string { @@ -297,8 +437,7 @@ var _ = Describe("CreateCluster", func() { } chooseWorkerVMI := func() *kubevirtv1.VirtualMachineInstance { - vmiList := &kubevirtv1.VirtualMachineInstanceList{} - err := k8sclient.List(context.Background(), vmiList, client.InNamespace(namespace)) + vmiList, err := virtClient.VirtualMachineInstance(namespace).List(&metav1.ListOptions{}) Expect(err).ToNot(HaveOccurred()) var chosenVMI *kubevirtv1.VirtualMachineInstance @@ -418,6 +557,18 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt machines to be ready") waitForMachineReadiness(2, 0) + + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + + By("posting calico CNI manifests to the guest cluster and waiting for network") + installCalicoCNI() + + By("Waiting for node readiness") + waitForNodeReadiness() + + By("waiting all tenant Pods to be Ready") + waitForTenantPods() }) It("should remediate a running VMI marked as being in a terminal state", Label("ephemeralVMs"), func() { @@ -445,6 +596,9 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt machines to be ready") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + By("creating machine health check") postDefaultMHC("kvcluster") @@ -457,7 +611,7 @@ var _ = Describe("CreateCluster", func() { Expect(ok).To(BeTrue()) chosenVMI.Labels[infrav1.KubevirtMachineVMTerminalLabel] = "marked-terminal-by-func-test" - err = k8sclient.Update(context.Background(), chosenVMI) + chosenVMI, err = virtClient.VirtualMachineInstance(namespace).Update(chosenVMI) Expect(err).ToNot(HaveOccurred()) By("Wait for KubeVirtMachine is deleted due to remediation") @@ -472,6 +626,18 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt new machines to be ready after remediation") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + + By("posting calico CNI manifests to the guest cluster and waiting for network") + installCalicoCNI() + + By("Waiting for node readiness") + waitForNodeReadiness() + + By("waiting all tenant Pods to be Ready") + waitForTenantPods() + }) It("should remediate failed unrecoverable VMI ", Label("ephemeralVMs"), func() { @@ -500,6 +666,9 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt machines to be ready") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + By("creating machine health check") postDefaultMHC("kvcluster") @@ -508,20 +677,13 @@ var _ = Describe("CreateCluster", func() { chosenVMI := chooseWorkerVMI() By("Setting VM to runstrategy once") - chosenVM := &kubevirtv1.VirtualMachine{ - ObjectMeta: metav1.ObjectMeta{ - Name: chosenVMI.Name, - Namespace: chosenVMI.Namespace, - }, - } - key := client.ObjectKey{Namespace: chosenVM.Namespace, Name: chosenVM.Name} - err = k8sclient.Get(context.Background(), key, chosenVM) + chosenVM, err := virtClient.VirtualMachine(chosenVMI.Namespace).Get(chosenVMI.Name, &metav1.GetOptions{}) Expect(err).ToNot(HaveOccurred()) once := kubevirtv1.RunStrategyOnce chosenVM.Spec.RunStrategy = &once - err = k8sclient.Update(context.Background(), chosenVM) + _, err = virtClient.VirtualMachine(namespace).Update(chosenVM) Expect(err).ToNot(HaveOccurred()) By("killing the chosen VMI's pod") @@ -542,6 +704,9 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt new machines to be ready after remediation") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + }) It("creates a simple externally managed cluster ephemeral VMs", Label("ephemeralVMs", "externallyManaged"), func() { @@ -572,6 +737,9 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt machines to be ready") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + By("Waiting for all tenant nodes to get provider id") waitForNodeUpdate() @@ -610,9 +778,11 @@ var _ = Describe("CreateCluster", func() { By("Waiting on kubevirt machines to be ready") waitForMachineReadiness(2, 0) + By("Waiting for getting access to the tenant cluster") + waitForTenantAccess(2) + By("Selecting a worker node to restart") - vmiList := &kubevirtv1.VirtualMachineInstanceList{} - err = k8sclient.List(context.Background(), vmiList, client.InNamespace(namespace)) + vmiList, err := virtClient.VirtualMachineInstance(namespace).List(&metav1.ListOptions{}) Expect(err).ToNot(HaveOccurred()) var chosenVMI *kubevirtv1.VirtualMachineInstance @@ -625,7 +795,7 @@ var _ = Describe("CreateCluster", func() { Expect(chosenVMI).ToNot(BeNil()) By(fmt.Sprintf("By restarting worker node hosted in vmi %s", chosenVMI.Name)) - err = k8sclient.Delete(context.Background(), chosenVMI) + err = virtClient.VirtualMachineInstance(namespace).Delete(chosenVMI.Name, &metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) By("Expecting a KubevirtMachine to revert back to ready=false while VM restarts") @@ -633,5 +803,241 @@ var _ = Describe("CreateCluster", func() { By("Expecting both KubevirtMachines stabilize to a ready=true again.") waitForMachineReadiness(2, 0) + + By("Waiting for getting access to the tenant cluster") + clientSet := waitForTenantAccess(2) + + By("posting calico CNI manifests to the guest cluster and waiting for network") + installCalicoCNI() + + By("Waiting for node readiness") + waitForNodeReadiness() + + By("waiting all tenant Pods to be Ready") + waitForTenantPods() + + vmiName := chosenVMI.Name + + By("read the VMI again after it was recreated") + recreatedVMI := getRecreatedVMI(vmiName, namespace, chosenVMI.GetUID()) + + Expect(*recreatedVMI.Spec.EvictionStrategy).Should(Equal(kubevirtv1.EvictionStrategyExternal)) + + By("Set a testFinalizer to hold the VMI deletion so we could query it after eviction") + recreatedVMI = addFinalizerFromVMI(recreatedVMI.Name, namespace) + + By("Get VMI's pod") + pod := getVMIPod(recreatedVMI) + + By("Try to evict the VMI pod; should fail, but trigger the VMI draining") + evictNode(pod) + + By("wait for a VMI to be marked for deletion") + waitForVMIDraining(vmiName, namespace) + + By("remove the test finalizer") + removeFinalizerFromVMI(recreatedVMI) + + By("wait for a new VMI to be created") + getRecreatedVMI(vmiName, namespace, recreatedVMI.GetUID()) + + By("Read the worker node from the tenant cluster, and validate its IP") + validateNewNodeIP(clientSet, vmiName, namespace) + }) + + // This test will create a tenant cluster from `templates/cluster-template-ext-infra.yaml` template. + // 1. generate secret in 'capk-system' namespace, containing external infra kubeconfig and namespace data + // (note, the kubeconfig actually points to the same cluster, which is okay for the sake of the test) + // 2. generate tenant cluster yaml manifests with `clusterctl generate cluster` command + // 3. apply generated tenant cluster yaml manifests + // 4. verify that tenant cluster machines booted and bootstrapped + // 5. verify that tenant cluster control plane came up successfully + It("should create a simple tenant cluster on external infrastructure", func() { + By("generating a secret with external infrastructure kubeconfig and namespace") + kubeconfig, err := os.ReadFile(os.Getenv("KUBECONFIG")) + Expect(err).ToNot(HaveOccurred()) + // replace api server url with default server value, so it's routable from CAPK pod + kubeconfigStr := string(kubeconfig) + m := regexp.MustCompile("(?m:(.*?server:).*$)") + kubeconfigStr = m.ReplaceAllString(kubeconfigStr, "${1} https://kubernetes.default") + externalInfraSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "external-infra-kubeconfig", + Namespace: "capk-system", + }, + Data: map[string][]byte{ + "namespace": []byte(namespace), + "kubeconfig": []byte(kubeconfigStr), + }, + } + err = k8sclient.Create(context.Background(), externalInfraSecret) + Expect(err).ToNot(HaveOccurred()) + + By("generating cluster manifests from example template") + cmd := exec.Command(ClusterctlPath, "generate", "cluster", "kvcluster", + "--from", "templates/cluster-template-ext-infra.yaml", + "--kubernetes-version", os.Getenv("TENANT_CLUSTER_KUBERNETES_VERSION"), + "--control-plane-machine-count=1", + "--worker-machine-count=1", + "--target-namespace", namespace) + stdout, _ := RunCmd(cmd) + err = os.WriteFile(manifestsFile, stdout, 0644) + Expect(err).ToNot(HaveOccurred()) + + By("applying cluster manifests") + cmd = exec.Command(KubectlPath, "apply", "-f", manifestsFile) + RunCmd(cmd) + + By("waiting for machines to be ready") + waitForMachineReadiness(2, 0) + + By("waiting for machines to bootstrap") + waitForBootstrappedMachines() + + By("waiting for control plane") + waitForControlPlane() }) }) + +func waitForVMIDraining(vmiName, namespace string) { + var vmi *kubevirtv1.VirtualMachineInstance + var err error + + By("wait for VMI is marked for deletion") + Eventually(func(g Gomega) bool { + vmi, err = virtClient.VirtualMachineInstance(namespace).Get(vmiName, &metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + + vmiDebugPrintout(vmi) + + g.Expect(vmi.Status.EvacuationNodeName).ShouldNot(BeEmpty()) + g.Expect(vmi.DeletionTimestamp).ShouldNot(BeNil()) + + return true + }).WithOffset(1). + WithTimeout(time.Minute * 2). + WithPolling(time.Second). + Should(BeTrue()) +} + +func evictNode(pod *corev1.Pod) { + + err := virtClient.CoreV1().Pods(pod.Namespace).EvictV1beta1(context.Background(), &policy.Eviction{ + ObjectMeta: metav1.ObjectMeta{ + Name: pod.Name, + }, + DeleteOptions: &metav1.DeleteOptions{ + GracePeriodSeconds: pointer.Int64(60 * 10), // 10 minutes + }, + }) + + ExpectWithOffset(1, k8serrors.IsTooManyRequests(err)).To(BeTrue(), "should return TooManyRequests error; got %v instead", err) +} + +func getRecreatedVMI(vmiName string, namespace string, originalUID types.UID) *kubevirtv1.VirtualMachineInstance { + var ( + vmi *kubevirtv1.VirtualMachineInstance + err error + ) + Eventually(func(g Gomega) types.UID { + vmi, err = virtClient.VirtualMachineInstance(namespace).Get(vmiName, &metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(vmi).ShouldNot(BeNil()) + + vmiDebugPrintout(vmi) + + g.Expect(vmi.Status.EvacuationNodeName).Should(BeEmpty()) + g.Expect(vmi.DeletionTimestamp).Should(BeNil()) + + return vmi.GetUID() + + }).WithOffset(1). + WithTimeout(time.Minute * 5). + WithPolling(time.Second * 5). + ShouldNot(Equal(originalUID)) // make sure that a new VMI was created + + return vmi +} + +func validateNewNodeIP(cl *kubernetes.Clientset, vmiName, namespace string) { + Eventually(func(g Gomega) bool { + // reading the node and the VMI again and again, because it takes time to the IPs to be synchronized + node, err := cl.CoreV1().Nodes().Get(context.Background(), vmiName, metav1.GetOptions{}) + g.Expect(err).ToNot(HaveOccurred()) + + var nodeIp string + for _, address := range node.Status.Addresses { + if address.Type == "InternalIP" { + nodeIp = address.Address + } + } + + g.Expect(nodeIp).ShouldNot(BeEmpty(), "node's IP is not set") + + vmi, err := virtClient.VirtualMachineInstance(namespace).Get(vmiName, &metav1.GetOptions{}) + + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(vmi).ShouldNot(BeNil()) + + for _, ifs := range vmi.Status.Interfaces { + for _, ip := range ifs.IPs { + if ip == nodeIp { + return true + } + } + } + return false + + }).WithTimeout(5 * time.Minute). + WithOffset(1). + WithPolling(10 * time.Second). + Should(BeTrue()) +} + +func vmiDebugPrintout(vmi *kubevirtv1.VirtualMachineInstance) { + GinkgoWriter.Printf(`[Debug] VMI: {"UID": "%v", "DeletionTimestamp": "%v", "EvacuationNodeName": "%s"}`+"\n", + vmi.UID, vmi.DeletionTimestamp, vmi.Status.EvacuationNodeName) +} + +func addFinalizerFromVMI(vmiName, namespace string) *kubevirtv1.VirtualMachineInstance { + var ( + vmi *kubevirtv1.VirtualMachineInstance + err error + ) + Eventually(func() error { + vmi, err = virtClient.VirtualMachineInstance(namespace).Get(vmiName, &metav1.GetOptions{}) + if err != nil { + return err + } + + vmi.Finalizers = append(vmi.Finalizers, testFinalizer) + _, err = virtClient.VirtualMachineInstance(vmi.Namespace).Update(vmi) + return err + }).WithOffset(1). + WithTimeout(time.Minute). + WithPolling(2 * time.Second). + Should(Succeed()) + + return vmi +} + +func removeFinalizerFromVMI(vmi *kubevirtv1.VirtualMachineInstance) { + index := -1 + for i, finalizer := range vmi.Finalizers { + if finalizer == testFinalizer { + index = i + break + } + } + ExpectWithOffset(1, index).To(BeNumerically(">=", 0)) + + patch := []byte(fmt.Sprintf(`[{"op": "remove", "path": "/metadata/finalizers/%d"}]`, index)) + + Eventually(func() error { + _, err := virtClient.VirtualMachineInstance(vmi.Namespace).Patch(vmi.Name, types.JSONPatchType, patch, &metav1.PatchOptions{}) + return err + }).WithOffset(1). + WithTimeout(time.Minute). + WithPolling(2 * time.Second). + Should(Succeed()) +} diff --git a/go.mod b/go.mod index 70708b1ad..f5db8e06b 100644 --- a/go.mod +++ b/go.mod @@ -1,22 +1,26 @@ module sigs.k8s.io/cluster-api-provider-kubevirt -go 1.17 +go 1.18 require ( - github.com/go-logr/logr v1.2.0 + github.com/go-logr/logr v1.2.3 + github.com/golang/glog v1.0.0 github.com/golang/mock v1.6.0 - github.com/onsi/ginkgo/v2 v2.1.3 - github.com/onsi/gomega v1.17.0 + github.com/onsi/ginkgo/v2 v2.1.4 + github.com/onsi/gomega v1.19.0 github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.3.0 github.com/spf13/pflag v1.0.5 golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 - k8s.io/api v0.23.1 - k8s.io/apimachinery v0.23.1 - k8s.io/client-go v0.23.1 + k8s.io/api v0.23.5 + k8s.io/apimachinery v0.23.5 + k8s.io/client-go v12.0.0+incompatible k8s.io/component-base v0.23.1 - k8s.io/klog/v2 v2.30.0 - kubevirt.io/api v0.51.0 + k8s.io/klog/v2 v2.40.1 + k8s.io/kubectl v0.22.2 + k8s.io/utils v0.0.0-20211116205334-6203023598ed + kubevirt.io/api v0.53.0 + kubevirt.io/client-go v0.0.0-00010101000000-000000000000 sigs.k8s.io/cluster-api v0.3.11-0.20210525210043-6c7878e7b4a9 sigs.k8s.io/controller-runtime v0.11.0-beta.0.0.20211110210527-619e6b92dab9 sigs.k8s.io/kind v0.11.0 @@ -25,40 +29,73 @@ require ( require ( cloud.google.com/go v0.99.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/coreos/prometheus-operator v0.38.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-kit/kit v0.9.0 // indirect + github.com/go-logfmt/logfmt v0.5.0 // indirect github.com/go-logr/zapr v1.2.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/swag v0.21.1 // indirect github.com/gobuffalo/flect v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.1.2 // indirect github.com/googleapis/gnostic v0.5.5 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20191119172530-79f836b90111 // indirect + github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/openshift/custom-resource-status v0.0.0-20200602122900-c002fd1547ca // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/openshift/api v0.0.0-20210105115604-44119421ec6b // indirect + github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47 // indirect + github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/pborman/uuid v1.2.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.11.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.28.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect + github.com/russross/blackfriday v1.5.2 // indirect + github.com/stretchr/testify v1.7.0 // indirect + github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.19.1 // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect - golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect + golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect @@ -68,12 +105,14 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/apiextensions-apiserver v0.23.1 // indirect - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect - kubevirt.io/containerized-data-importer-api v1.42.0 // indirect + k8s.io/cli-runtime v0.23.1 // indirect + k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect + kubevirt.io/containerized-data-importer-api v1.47.0 // indirect kubevirt.io/controller-lifecycle-operator-sdk v0.2.1 // indirect sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/kustomize/api v0.10.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect ) replace ( @@ -81,3 +120,8 @@ replace ( sigs.k8s.io/apiserver-network-proxy/konnectivity-client => sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.24 sigs.k8s.io/cluster-api => sigs.k8s.io/cluster-api v1.0.0 ) + +replace ( + k8s.io/client-go => k8s.io/client-go v0.23.1 + kubevirt.io/client-go => kubevirt.io/client-go v0.53.0 +) diff --git a/go.sum b/go.sum index 900d8b820..8a942ad05 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= @@ -44,25 +45,42 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= +github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -73,26 +91,41 @@ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30/go.mod h1:4AJxUpXUhv4N+ziTvIcWWXgeorXpxPZOfk9HdEVr96M= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -103,14 +136,20 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brancz/gojsontoyaml v0.0.0-20190425155809-e8bd32d46b3d/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0= +github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= +github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -135,13 +174,18 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/coredns/caddy v1.1.0 h1:ezvsPrT/tA/7pYDBZxu0cT0VmWk75AfIaf6GSYCNMf0= github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.13 h1:ld5RswmH1xjqBUEukw4QxC1PakLNNoVlsZEV8FGwoV8= github.com/coredns/corefile-migration v1.0.13/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= +github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -149,11 +193,16 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/prometheus-operator v0.38.0 h1:gF2xYIfO09XLFdyEecND46uihQ2KTaDwTozRZpXLtN4= +github.com/coreos/prometheus-operator v0.38.0/go.mod h1:xZC7/TgeC0/mBaJk+1H9dbHaiEvLYHgX6Mi1h40UPh8= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -162,17 +211,33 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/drone/envsubst/v2 v2.0.0-20210615175204-7bf45dbf5372/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY= +github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.10.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.15.0+incompatible h1:8KpYO/Xl/ZudZs5RNOEhWMBY4hmzlZhhRd9cu+jrZP4= +github.com/emicklei/go-restful v2.15.0+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -186,6 +251,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.0.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -193,15 +259,19 @@ github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.2.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -211,58 +281,122 @@ github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSy github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.2/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= github.com/gobuffalo/flect v0.2.3 h1:f/ZukRnSNA/DUpSNDadko7Qc0PhGvsew35p/2tu+CRY= github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -296,10 +430,13 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= @@ -319,6 +456,7 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-github/v33 v33.0.0/go.mod h1:GMdDnVZY/2TsWgp/lkYnpSAh6TrzhANBBwm6k6TTEXg= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= @@ -329,6 +467,7 @@ github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIG github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -343,39 +482,60 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -384,20 +544,26 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -405,39 +571,52 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.0.0-20171009183408-7fe0c75c13ab/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jsonnet-bundler/jsonnet-bundler v0.2.0/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20191119172530-79f836b90111 h1:Lq6HJa0JqSg5ko/mkizFWlpIrY7845g9Dzz9qeD5aXI= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v0.0.0-20191119172530-79f836b90111/go.mod h1:MP2HbArq3QT+oVp8pmtHNZnSnkhdkHtDnc7h6nJXmBU= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -453,56 +632,84 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0 h1:nHHjmvjitIiyPlUHk/ofpgvBcNcawJLtf4PYHORLjAA= +github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0/go.mod h1:YBCo4DoEeDndqvAn6eeu0vWM7QdXmHEeI9cFWplmBys= github.com/kubevirt/containerized-data-importer-api v1.41.1-0.20211201033752-05520fb9f18d h1:4HESRlaHoCI+w9AtL/TAcGPCqwPOpz+sHUlYHoM78XE= github.com/kubevirt/containerized-data-importer-api v1.41.1-0.20211201033752-05520fb9f18d/go.mod h1:Ty5GJ+6nKlpcBKjeebb/e6IrF8bNFgOus9hfuMjEt6A= +github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -512,7 +719,10 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -523,22 +733,30 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -546,13 +764,26 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/openshift/custom-resource-status v0.0.0-20200602122900-c002fd1547ca h1:F1MEnOMwSrTA0YAkO0he9ip9w0JhYzI/iCB2mXmaSPg= +github.com/openshift/api v0.0.0-20210105115604-44119421ec6b h1:9wG43AJGupRUUAAF/GN2CtQgVlo+BzdIlmsTwUlIATE= +github.com/openshift/api v0.0.0-20210105115604-44119421ec6b/go.mod h1:aqU5Cq+kqKKPbDMqxo9FojgDeSpNJI7iuskjXjtojDg= +github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE= +github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47 h1:+TEY29DK0XhqB7HFC9OfV8qf3wffSyi7MWv3AP28DGQ= +github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47/go.mod h1:u7NRAjtYVAKokiI9LouzTv4mhds8P4S1TwdVAfbjKSk= github.com/openshift/custom-resource-status v0.0.0-20200602122900-c002fd1547ca/go.mod h1:GDjWl0tX6FNIj82vIxeudWeSx2Ff6nDZ8uJn0ohUFvo= +github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= +github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= +github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw= +github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= @@ -561,7 +792,9 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -573,59 +806,97 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE= +github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= +github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= +github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI= +github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= +github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= @@ -634,6 +905,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= @@ -647,6 +919,7 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= @@ -655,6 +928,7 @@ github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -665,13 +939,22 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -680,10 +963,16 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk= +go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY= +go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE= +go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= @@ -695,6 +984,11 @@ go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lL go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -714,21 +1008,26 @@ go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= @@ -738,13 +1037,20 @@ go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -789,17 +1095,21 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -809,9 +1119,14 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -837,6 +1152,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -844,10 +1160,13 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -885,26 +1204,39 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -925,6 +1257,7 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -945,6 +1278,7 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -957,24 +1291,27 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -987,15 +1324,19 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1007,16 +1348,22 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1061,6 +1408,7 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1072,6 +1420,7 @@ gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCY gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1106,6 +1455,7 @@ google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUb google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= @@ -1118,9 +1468,12 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -1180,11 +1533,16 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1232,9 +1590,11 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -1245,6 +1605,7 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1254,13 +1615,17 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1268,84 +1633,127 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= +k8s.io/api v0.0.0-20181115043458-b799cb063522/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20190725062911-6607c48751ae/go.mod h1:1O0xzX/RAtnm7l+5VEUxZ1ysO2ghatfq/OZED4zM9kA= +k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58= +k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= +k8s.io/api v0.0.0-20191115095533-47f6de673b26/go.mod h1:iA/8arsvelvo4IDqIhX4IbjTEKBGgvsf2OraTuRtLFU= +k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0= +k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw= +k8s.io/api v0.20.0/go.mod h1:HyLC5l5eoS/ygQYl1BXBgFzWNlkHiAuyNAbevIn+FKg= k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/api v0.23.0-alpha.4/go.mod h1:C2RqQ86jH9nM0YFGjLhKlfldBYLnBEb5sn+x50lF2zg= -k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8= k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo= +k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= +k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA= +k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= +k8s.io/apiextensions-apiserver v0.17.3/go.mod h1:CJbCyMfkKftAd/X/V6OTHYhVn7zXnDdnkUjS1h0GTeY= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= k8s.io/apiextensions-apiserver v0.20.2/go.mod h1:F6TXp389Xntt+LUq3vw6HFOLttPa0V8821ogLGwb6Zs= k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= -k8s.io/apiextensions-apiserver v0.23.0-alpha.4/go.mod h1:kigfmoeWZRvDkUtNCLd4vEVmVHU2jhi/8ISvK2v724c= k8s.io/apiextensions-apiserver v0.23.1 h1:xxE0q1vLOVZiWORu1KwNRQFsGWtImueOrqSl13sS5EU= k8s.io/apiextensions-apiserver v0.23.1/go.mod h1:0qz4fPaHHsVhRApbtk3MGXNn2Q9M/cVWWhfHdY2SxiM= +k8s.io/apimachinery v0.0.0-20181110190943-2a7c93004028/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190719140911-bfcf53abc9f8/go.mod h1:sBJWIJZfxLhp7mRsRyuAE/NfKTr3kXGR1iaqg8O0gJo= +k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8= +k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= +k8s.io/apimachinery v0.0.0-20191115015347-3c7067801da2/go.mod h1:dXFS2zaQR8fyzuvRdJDHw2Aerij/yVGJSre0bZQSVJA= +k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apimachinery v0.23.0-alpha.4/go.mod h1:oyH3LcOKLLooQH1NlpHlilzkWxqsiHWETyHgssntcXg= -k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo= k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno= +k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= +k8s.io/apiserver v0.17.3/go.mod h1:iJtsPpu1ZpEnHaNawpSV0nYTGBhhX2dUlnn7/QS7QiY= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.2/go.mod h1:2nKd93WyMhZx4Hp3RfgH2K5PhwyTrprrkWYnI7id7jA= k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= -k8s.io/apiserver v0.23.0-alpha.4/go.mod h1:filg3J7fRj+AuwLTFXNcH566LHC8mLkQrD0H2zUVpJk= k8s.io/apiserver v0.23.1 h1:vWGf8LcV9Pk/z5rdLmCiBDqE21ccbe930dzrtVMhw9g= k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY= k8s.io/cli-runtime v0.22.2/go.mod h1:tkm2YeORFpbgQHEK/igqttvPTRIHFRz5kATlw53zlMI= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= -k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= -k8s.io/client-go v0.23.0-alpha.4/go.mod h1:OBGvnY60bm0zXmY4unHcYUHmffR6Smg2AqJ3pzORKYk= +k8s.io/cli-runtime v0.23.1 h1:vHUZrq1Oejs0WaJnxs09mLHKScvIIl2hMSthhS8o8Yo= +k8s.io/cli-runtime v0.23.1/go.mod h1:r9r8H/qfXo9w+69vwUL7LokKlLRKW5D6A8vUKCx+YL0= k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ= k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0= k8s.io/cluster-bootstrap v0.22.2 h1:jP6Nkp3CdSfr50cAn/7WGsNS52zrwMhvr0V+E3Vkh/w= k8s.io/cluster-bootstrap v0.22.2/go.mod h1:ZkmQKprEqvrUccMnbRHISsMscA1dsQ8SffM9nHq6CgE= +k8s.io/code-generator v0.0.0-20181114232248-ae218e241252/go.mod h1:IPqxl/YHk05nodzupwjke6ctMjyNRdV2zZ5/j3/F204= k8s.io/code-generator v0.0.0-20190717022600-77f3a1fe56bb/go.mod h1:cDx5jQmWH25Ff74daM7NVYty9JWw9dvIS9zT9eIubCY= +k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= +k8s.io/code-generator v0.17.3/go.mod h1:l8BLVwASXQZTo2xamW5mQNFCe1XPiAesVq7Y1t7PiQQ= +k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= k8s.io/code-generator v0.20.2/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= -k8s.io/code-generator v0.23.0-alpha.4/go.mod h1:alK4pz5+y/zKXOPBnND3TvXOC/iF2oYTBDynHO1+qlI= k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA= +k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA= +k8s.io/component-base v0.17.3/go.mod h1:GeQf4BrgelWm64PXkIXiPh/XS0hnO42d9gx9BtbZRp8= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0= k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= -k8s.io/component-base v0.23.0-alpha.4/go.mod h1:CD9PHLOKNi/x4tJLxoLaLA2EPkCeiT/1m/8PpPxwp80= k8s.io/component-base v0.23.1 h1:j/BqdZUWeWKCy2v/jcgnOJAzpRYWSbGcjGVYICko8Uc= k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo= k8s.io/component-helpers v0.22.2/go.mod h1:+N61JAR9aKYSWbnLA88YcFr9K/6ISYvRNybX7QW7Rs8= +k8s.io/gengo v0.0.0-20181106084056-51747d6e00da/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190907103519-ebc107f98eab/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68= +k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.40.1 h1:P4RRucWk/lFOlDdkAr3mc7iWFkgKrZY9qZMAgek06S4= +k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20181114233023-0317810137be/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20210817084001-7fbd8d59e5b8/go.mod h1:foAE7XkrXQ1Qo2eWsW/iWksptrVdbl6t+vscSdmmGjk= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf h1:M9XBsiMslw2lb2ZzglC0TOkBPK5NQi0/noUrdnoFwUg= +k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kubectl v0.22.2 h1:KMyYNZoBshaL3XKx04X07DtpoD4vMrdkfiN/G2Qx/PU= k8s.io/kubectl v0.22.2/go.mod h1:BApg2j0edxLArCOfO0ievI27EeTQqBDMNU9VQH734iQ= k8s.io/metrics v0.22.2/go.mod h1:GUcsBtpsqQD1tKFS/2wCKu4ZBowwRncLOJH1rgWs3uw= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -kubevirt.io/api v0.51.0 h1:G7nQDBkEzAxdSgpAPzE9ldXBIv8m0OtsgKWIUc+tvOw= -kubevirt.io/api v0.51.0/go.mod h1:RPYFWI69OVi7i6YtW5gHN3fjYsjlRfRilKVNcpxEMmM= +k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +kubevirt.io/api v0.53.0 h1:BXr595WisL1dB59eUt/QbvuLKR8GfRzaZ0p5piTIL6k= +kubevirt.io/api v0.53.0/go.mod h1:mK8ilpVLcZraqgo7hv2OSNQ5vdsA3G9Pxn8LY2/1+IY= +kubevirt.io/client-go v0.53.0 h1:4vAeoEHz7YS6PUyj0KxxyZhMyqFzVkQezmBHgwWp8y8= +kubevirt.io/client-go v0.53.0/go.mod h1:3FN4GQaV8iJEaRZgc63FVJ+ytk82s2pRumFUB9xs+MY= kubevirt.io/controller-lifecycle-operator-sdk v0.2.1 h1:I1b14fnhwrVvQLmgksMo9vgje42hmH4QN5kqyYDqbMA= kubevirt.io/controller-lifecycle-operator-sdk v0.2.1/go.mod h1:ZJhLceiY2Gl5CXFGSp5eMGt/sksOiJP0289nAZFCQf0= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= @@ -1363,20 +1771,28 @@ sigs.k8s.io/controller-runtime v0.8.3/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/controller-runtime v0.11.0-beta.0.0.20211110210527-619e6b92dab9 h1:FMpUSA0G4eqxTpUiyVe1QoTWWj9yjVClQOSaYDXWkWw= sigs.k8s.io/controller-runtime v0.11.0-beta.0.0.20211110210527-619e6b92dab9/go.mod h1:zbtXsL/EF7Jejm73ivV4QOuyM2kg13WCz3Up+Agc1gE= +sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA= sigs.k8s.io/controller-tools v0.5.0/go.mod h1:JTsstrMpxs+9BUj6eGuAaEb6SDSPTeVtUyp0jmnAM/I= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/kind v0.11.0 h1:tBxAEht9B3Dln8+kLxDg+A23ViRWcXquhV1Fe195fbE= sigs.k8s.io/kind v0.11.0/go.mod h1:fRpgVhtqAWrtLB9ED7zQahUimpUXuG/iHT88xYqEGIA= sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g= +sigs.k8s.io/kustomize/api v0.10.1 h1:KgU7hfYoscuqag84kxtzKdEC3mKMb99DPI3a0eaV1d0= +sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8= sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs= sigs.k8s.io/kustomize/kustomize/v4 v4.2.0/go.mod h1:MOkR6fmhwG7hEDRXBYELTi5GSFcLwfqwzTRHW3kv5go= sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= +sigs.k8s.io/kustomize/kyaml v0.13.0 h1:9c+ETyNfSrVhxvphs+K2dzT3dh5oVPPEqPOE/cUpScY= +sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/hack/functest.sh b/hack/functest.sh index 23aca0c81..098e38b5f 100755 --- a/hack/functest.sh +++ b/hack/functest.sh @@ -13,10 +13,10 @@ echo "Building and installing capk manager container" echo "Running e2e test suite" export KUBECONFIG=$(./kubevirtci kubeconfig) -export NODE_VM_IMAGE_TEMPLATE=quay.io/kubevirtci/fedora-kubeadm:35 +export NODE_VM_IMAGE_TEMPLATE=quay.io/capk/ubuntu-2004-container-disk:v1.22.0 export IMAGE_REPO=k8s.gcr.io -export TENANT_CLUSTER_KUBERNETES_VERSION=v1.21.0 -export CRI_PATH=/var/run/crio/crio.sock -export ROOT_VOLUME_SIZE=23Gi -export STORAGE_CLASS_NAME=rook-ceph-block +export TENANT_CLUSTER_KUBERNETES_VERSION=v1.22.0 +export CRI_PATH=/var/run/containerd/containerd.sock +export ROOT_VOLUME_SIZE=13Gi +export STORAGE_CLASS_NAME=local make e2e-test diff --git a/hack/run-e2e.sh b/hack/run-e2e.sh index 2b5d8d433..e7a7c0b4d 100755 --- a/hack/run-e2e.sh +++ b/hack/run-e2e.sh @@ -22,4 +22,4 @@ fi rm -rf $TEST_WORKING_DIR mkdir -p $TEST_WORKING_DIR -$BIN_DIR/e2e.test --kubectl-path $KUBECTL_PATH --clusterctl-path $CLUSTERCTL_PATH --working-dir $TEST_WORKING_DIR +$BIN_DIR/e2e.test -ginkgo.v --kubectl-path $KUBECTL_PATH --clusterctl-path $CLUSTERCTL_PATH --working-dir $TEST_WORKING_DIR diff --git a/kubevirtci b/kubevirtci index 1eb704766..8e12381a6 100755 --- a/kubevirtci +++ b/kubevirtci @@ -1,55 +1,89 @@ #!/bin/bash -# Usage: -# -# ./kubevirtci up # start a cluster with kubevirt, cert-manager and capi -# ./kubevirtci sync # build and deploy current capik -# ./kubevirtci kubectl get pods --all-namespaces # interact with the cluster -# ./kubevirtci clusterctl create cluster # run clusterctl commands against the cluster -# ./kubevirtci oc get pods --all-namespaces # interact with the HOSTED cluster -# ./kubevirtci down # destroy the cluster - set -e -export KUBEVIRT_PROVIDER=${KUBEVIRT_PROVIDER:-k8s-1.21} -export KUBEVIRTCI_TAG=${KUBEVIRTCI_TAG:-2110251848-8198e9c} +export KUBEVIRT_PROVIDER=${KUBEVIRT_PROVIDER:-k8s-1.23} +export CAPK_GUEST_K8S_VERSION=${CAPK_GUEST_K8S_VERSION:-v1.22.0} +export KUBEVIRTCI_TAG=${KUBEVIRTCI_TAG:-2205231118-f12b50e} export KUBECONFIG=$(cluster-up/cluster-up/kubeconfig.sh) export KUBEVIRT_DEPLOY_PROMETHEUS=false export KUBEVIRT_DEPLOY_CDI=false export KUBEVIRT_NUM_NODES=${KUBEVIRT_NUM_NODES:-1} export KUBEVIRT_MEMORY_SIZE=${KUBEVIRT_MEMORY_SIZE:-15360M} export KUBEVIRT_DEPLOY_CDI="true" -export KUBEVIRT_STORAGE="rook-ceph-default" +export METALLB_VERSION="v0.12.1" +export CAPK_RELEASE_VERSION="v0.1.0-rc.0" +export CLUSTERCTL_VERSION="v1.0.0" +export CALICO_VERSION="v3.21" +export KUBEVIRT_VERSION="v0.53.0" +export NODE_VM_IMAGE_TEMPLATE=${NODE_VM_IMAGE_TEMPLATE:-quay.io/capk/ubuntu-2004-container-disk:v1.22.0} _default_bin_path=./hack/tools/bin +_default_tmp_path=./hack/tools/bin/tmp _default_clusterctl_path=./hack/tools/bin/clusterctl _default_virtctl_path=./hack/tools/bin/virtctl export CLUSTERCTL_PATH=${CLUSTERCTL_PATH:-${_default_clusterctl_path}} +export TENANT_CLUSTER_NAME=${TENANT_CLUSTER_NAME:-kvcluster} +export TENANT_CLUSTER_NAMESPACE=${TENANT_CLUSTER_NAMESPACE:-kvcluster} _kubectl=cluster-up/cluster-up/kubectl.sh +_ssh_infra=cluster-up/cluster-up/ssh.sh _action=$1 shift +function kubevirtci::usage() { + echo "Usage: + + ./kubevirtci + + Commands: + + up Start a cluster with kubevirt, cert-manager and capi + sync Build and deploy current capk from source (must be executed from within capk source tree) + down Destroy the cluster + refresh Build current capk and trigger creating new capk pods + clean-cache Removes all files cached by kubevirtci + + kubeconfig Return the kubeconfig of the cluster + kubectl Interact with the cluster + kubectl-tenant Interact with the tenant cluster + virtctl Run virtctl commands against the cluster + clusterctl Run clusterctl commands against the cluster + + install-capk Installs capk from published release manifests + install-metallb Installs metallb into the infra cluster + install-calico Installs calico cni into tenant cluster + curl-lb [lb namespace] Curls lb service within infra cluster + + ssh-infra SSH into one of the infra nodes (like node01) + ssh-tenant [vmi namespace] SSH into one of the guest nodes + create-cluster Create new kubernetes tenant cluster + create-external-cluster Create new kubernetes tenant cluster simulated as running on external infra + destroy-cluster Destroy the tenant cluster + + help Print usage + " +} + function kubevirtci::kubeconfig() { cluster-up/cluster-up/kubeconfig.sh } function kubevirtci::fetch_kubevirtci() { [[ -d cluster-up ]] || git clone https://github.com/kubevirt/kubevirtci.git cluster-up - (cd cluster-up && git checkout ${KUBEVIRTCI_TAG} > /dev/null) + (cd cluster-up && git checkout main > /dev/null 2>&1 && git pull > /dev/null && git checkout ${KUBEVIRTCI_TAG} > /dev/null 2>&1) mkdir -p ./hack/tools/bin/ if [ ! -f "${_default_clusterctl_path}" ]; then - echo >&2 "Downloading clusterctl ..." - curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.0.0/clusterctl-linux-amd64 -o ${_default_clusterctl_path} + echo >&2 "Downloading clusterctl version ${CLUSTERCTL_VERSION}..." + curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/${CLUSTERCTL_VERSION}/clusterctl-linux-amd64 -o ${_default_clusterctl_path} chmod u+x ${_default_clusterctl_path} fi if [ ! -f "${_default_virtctl_path}" ]; then echo >&2 "Downloading virtctl ..." - LATEST=$(curl -L https://storage.googleapis.com/kubevirt-prow/devel/release/kubevirt/kubevirt/stable.txt) - curl -L https://github.com/kubevirt/kubevirt/releases/download/${LATEST}/virtctl-${LATEST}-linux-amd64 -o ${_default_virtctl_path} + curl -L https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/virtctl-${KUBEVIRT_VERSION}-linux-amd64 -o ${_default_virtctl_path} chmod u+x ${_default_virtctl_path} fi } @@ -58,11 +92,12 @@ function kubevirtci::up() { make cluster-up -C cluster-up export KUBECONFIG=$(cluster-up/cluster-up/kubeconfig.sh) echo "installing kubevirt..." - LATEST=$(curl -L https://storage.googleapis.com/kubevirt-prow/devel/release/kubevirt/kubevirt/stable.txt) - ${_kubectl} apply -f https://github.com/kubevirt/kubevirt/releases/download/${LATEST}/kubevirt-operator.yaml - ${_kubectl} apply -f https://github.com/kubevirt/kubevirt/releases/download/${LATEST}/kubevirt-cr.yaml - echo "installing capi..." + ${_kubectl} apply -f https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-operator.yaml + curl -L https://github.com/kubevirt/kubevirt/releases/download/${KUBEVIRT_VERSION}/kubevirt-cr.yaml \ + | sed -e "s|\( \+\)\(featureGates:\).*$|\1\2\n\1- LiveMigration|" \ + | ${_kubectl} apply -f - + echo "installing capi..." cat << EOF > ${_default_bin_path}/clusterctl_config.yaml --- cert-manager: @@ -78,11 +113,28 @@ function kubevirtci::down() { } function kubevirtci::build() { - export REGISTRY="localhost:$(cluster-up/cluster-up/cli.sh ports registry)" + export REGISTRY="127.0.0.1:$(cluster-up/cluster-up/cli.sh ports registry)" make docker-build make docker-push } +function kubevirtci::ssh_tenant() { + vmi_name=$1 + vmi_namespace=${2:-$TENANT_CLUSTER_NAMESPACE} + + mkdir -p $_default_tmp_path + + echo "vmi $vmi_name namespace $vmi_namespace" + + ${_kubectl} get secret -n $TENANT_CLUSTER_NAMESPACE kvcluster-ssh-keys -o jsonpath='{.data}' | grep key | awk -F '"' '{print $4}' | base64 -d > ${_default_tmp_path}/key.pem + + chmod 600 ${_default_tmp_path}/key.pem + + ssh -o IdentitiesOnly=yes -o "ProxyCommand=$_default_virtctl_path port-forward --stdio=true $vmi_name.$vmi_namespace 22" capk@$vmi_name.$vmi_namespace -i ${_default_tmp_path}/key.pem + + rm ${_default_tmp_path}/key.pem +} + function kubevirtci::refresh() { ${_kubectl} delete pods --all -n capk-system } @@ -98,17 +150,191 @@ function kubevirtci::install() { function kubevirtci::generate_kubeconfig() { make clusterkubevirtadm-linux - bin/clusterkubevirtadm-linux-amd64 apply credentials --namespace e2e-test - bin/clusterkubevirtadm-linux-amd64 get kubeconfig --namespace=e2e-test --output-kubeconfig=kubeconfig-e2e + bin/clusterkubevirtadm-linux-amd64 apply credentials --namespace ${TENANT_CLUSTER_NAMESPACE} + bin/clusterkubevirtadm-linux-amd64 get kubeconfig --namespace=${TENANT_CLUSTER_NAMESPACE} --output-kubeconfig=kubeconfig-e2e sed -i -r 's/127.0.0.1:[0-9]+/192.168.66.101:6443/g' kubeconfig-e2e } +function kubevirtci::destroy_cluster() { + ${_kubectl} delete cluster -n ${TENANT_CLUSTER_NAMESPACE} ${TENANT_CLUSTER_NAME} --ignore-not-found +} + + function kubevirtci::create_cluster() { - export NODE_VM_IMAGE_TEMPLATE=quay.io/kubevirtci/fedora-kubeadm:35 export IMAGE_REPO=k8s.gcr.io - export CRI_PATH="/var/run/crio/crio.sock" - oc create secret generic external-infra-kubeconfig -n capk-system --from-file=kubeconfig=kubeconfig-e2e --from-literal=namespace=e2e-test - $CLUSTERCTL_PATH generate cluster kvcluster --kubernetes-version v1.21.0 --control-plane-machine-count=1 --worker-machine-count=1 --from templates/cluster-template-ext-infra.yaml | ${_kubectl} apply -f - + export CRI_PATH="/var/run/containerd/containerd.sock" + template=templates/cluster-template.yaml + + if [ ! -f $template ]; then + template="https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt/blob/main/templates/cluster-template.yaml" + fi + + echo "Using cluster template $template" + + $CLUSTERCTL_PATH generate cluster ${TENANT_CLUSTER_NAME} --target-namespace ${TENANT_CLUSTER_NAMESPACE} --kubernetes-version ${CAPK_GUEST_K8S_VERSION} --control-plane-machine-count=1 --worker-machine-count=1 --from $template | ${_kubectl} apply -f - + + echo "Wait for tenant cluster to be ready" + ${_kubectl} wait cluster -n kvcluster kvcluster --for=condition=Ready --timeout=5m + + echo "Wait for tenant cluster kubernetes apiserver up" + kubevirtci::retry_until_success kubevirtci::kubectl_tenant get pods -n kube-system + + echo "Waiting for worker VM in tenant cluster namespace" + kubevirtci::retry_until_success kubevirtci::vm_matches "${TENANT_CLUSTER_NAME}-md-" +} + + +function kubevirtci::create_external_cluster() { + export IMAGE_REPO=k8s.gcr.io + export CRI_PATH="/var/run/containerd/containerd.sock" + + ${_kubectl} delete secret external-infra-kubeconfig -n capk-system --ignore-not-found + ${_kubectl} create secret generic external-infra-kubeconfig -n capk-system --from-file=kubeconfig=kubeconfig-e2e --from-literal=namespace=${TENANT_CLUSTER_NAMESPACE} + $CLUSTERCTL_PATH generate cluster ${TENANT_CLUSTER_NAME} --target-namespace ${TENANT_CLUSTER_NAMESPACE} --kubernetes-version ${CAPK_GUEST_K8S_VERSION} --control-plane-machine-count=1 --worker-machine-count=1 --from templates/cluster-template-ext-infra.yaml | ${_kubectl} apply -f - +} + +function kubevirtci::create_tenant_namespace { + ${_kubectl} apply -f - < $metal_config +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: metallb-system + name: config +data: + config: | + address-pools: + - name: default + protocol: layer2 + addresses: + - 192.168.66.201-192.168.66.250 +EOF + + ${_kubectl} apply -f ${metal_config} + + rm $metal_config + echo "metallb installed!" +} + +function kubevirtci::curl_lb { + mkdir -p ${_default_tmp_path} + job_yaml=${_default_tmp_path}/curl-test-pod.yaml + if [ -f ${job_yaml} ]; then + ${_kubectl} delete -f ${job_yaml} --ignore-not-found + fi + + lb_name=$1 + lb_namespace=${2:-$TENANT_CLUSTER_NAMESPACE} + + $_kubectl get service $lb_name -n $lb_namespace + + lb_ip=$($_kubectl get service $lb_name -n $lb_namespace -o yaml | grep "ip:" | awk '{print $3}') + lb_port=$($_kubectl get service $lb_name -n $lb_namespace -o yaml | grep "port:" | awk '{print $2}') + + + cat << EOF > $job_yaml +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: curl-test-job + namespace: ${lb_namespace} +spec: + template: + spec: + containers: + - name: fedora + image: fedora:35 + command: + - curl + - "${lb_ip}:${lb_port}" + restartPolicy: Never + backoffLimit: 4 +EOF + + ${_kubectl} create -f $job_yaml + echo "-----------Waiting for curl job to complete" + ${_kubectl} wait job curl-test-job -n default --for condition=Complete --timeout=5m + + pod_name=$($_kubectl get pods --selector=job-name=curl-test-job --output=jsonpath='{.items[*].metadata.name}') + + echo "-----------CURL LOG FOR POD $pod_name" + $_kubectl logs -n default $pod_name 2>/dev/null + + ${_kubectl} delete -f ${job_yaml} --ignore-not-found > /dev/null 2>&1 +} + + +function kubevirtci::kubectl_tenant { + vms_list=$(${_kubectl} get vm -n ${TENANT_CLUSTER_NAMESPACE} --no-headers -o custom-columns=":metadata.name") + for vm in $vms_list + do + if [[ "$vm" == ${TENANT_CLUSTER_NAME}-control-plane* ]]; then + control_plane_vm_name=$vm + fi + done + if [ -n "${control_plane_vm_name}" ]; then + echo "Found control plane VM: ${control_plane_vm_name} in namespace ${TENANT_CLUSTER_NAMESPACE}" + else + echo "control-plane vm is not found in namespace ${TENANT_CLUSTER_NAMESPACE} (looking for regex ${TENANT_CLUSTER_NAME}-control-plane*)" + exit 1 + fi + ${_default_virtctl_path} port-forward -n ${TENANT_CLUSTER_NAMESPACE} vm/${control_plane_vm_name} 64443:6443 > /dev/null 2>&1 & + trap 'kill $(jobs -p) > /dev/null 2>&1' EXIT + rm -f .${TENANT_CLUSTER_NAME}-kubeconfig + $CLUSTERCTL_PATH get kubeconfig ${TENANT_CLUSTER_NAME} -n ${TENANT_CLUSTER_NAMESPACE} > .${TENANT_CLUSTER_NAME}-kubeconfig + sleep 0.1 + kubectl --kubeconfig .${TENANT_CLUSTER_NAME}-kubeconfig --insecure-skip-tls-verify --server https://localhost:64443 "$@" +} + +function kubevirtci::retry_until_success { + local timeout=30 + local interval=1 + until $@; do + ((timeout--)) && ((timeout==0)) && echo "condition not met" && exit 1 + echo "waiting for \"$@\"" + sleep $interval + done +} + +function kubevirtci::vm_matches { + local vm_name=$1 + ${_kubectl} get vm -n ${TENANT_CLUSTER_NAMESPACE} --no-headers -o custom-columns=":metadata.name" | grep -q $vm_name } kubevirtci::fetch_kubevirtci @@ -128,24 +354,64 @@ case ${_action} in kubevirtci::build kubevirtci::install ;; +"install-capk") + kubevirtci::install_capk_release + ;; +"install-metallb") + kubevirtci::install_metallb + ;; +"install-calico") + kubevirtci::install_calico + ;; +"curl-lb") + kubevirtci::curl_lb "$@" + ;; "kubeconfig") kubevirtci::kubeconfig ;; "kubectl") ${_kubectl} "$@" ;; +"kubectl-tenant") + kubevirtci::kubectl_tenant "$@" + ;; "virtctl") ${_default_virtctl_path} "$@" ;; +"ssh-infra") + $_ssh_infra "$@" + ;; +"ssh-tenant") + kubevirtci::ssh_tenant "$@" + ;; "clusterctl") $CLUSTERCTL_PATH "$@" ;; "create-cluster") - kubevirtci::generate_kubeconfig + kubevirtci::create_tenant_namespace kubevirtci::create_cluster ;; +"create-external-cluster") + kubevirtci::create_tenant_namespace + kubevirtci::generate_kubeconfig + kubevirtci::create_external_cluster + ;; +"destroy-cluster") + kubevirtci::destroy_cluster + ;; + +"clean-cache") + rm ${_default_clusterctl_path} + rm ${_default_virtctl_path} + rm -rf ${_default_tmp_path} + ;; +"help") + kubevirtci::usage + ;; *) - echo "No command provided, known commands are 'up', 'down', 'sync', 'kubectl', 'clusterctl', 'create-cluster', 'virtctl'" + echo "Error: Unknown kubevirtci command" + echo "" + kubevirtci::usage exit 1 ;; esac diff --git a/main.go b/main.go index 389faa53b..c3de12ece 100644 --- a/main.go +++ b/main.go @@ -163,6 +163,7 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { setupLog.Error(err, "unable to create controller", "controller", "reconciler") os.Exit(1) } + if err := (&controllers.KubevirtClusterReconciler{ Client: mgr.GetClient(), InfraCluster: infracluster.New(mgr.GetClient()), @@ -171,6 +172,11 @@ func setupReconcilers(ctx context.Context, mgr ctrl.Manager) { setupLog.Error(err, "unable to create controller", "controller", "KubevirtCluster") os.Exit(1) } + + if err := (controllers.NewVmiEvictionReconciler(mgr.GetClient())).SetupWithManager(ctx, mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VirtualMachineInstance") + os.Exit(1) + } } func setupWebhooks(mgr ctrl.Manager) { diff --git a/metadata.yaml b/metadata.yaml index 1045d3d75..0fe4fb548 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -6,6 +6,6 @@ apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 kind: Metadata releaseSeries: - - major: 0 + - major: 1 minor: 1 contract: v1beta1 diff --git a/pkg/infracluster/infracluster.go b/pkg/infracluster/infracluster.go index 2dfe71b9c..e88b2af59 100644 --- a/pkg/infracluster/infracluster.go +++ b/pkg/infracluster/infracluster.go @@ -6,58 +6,78 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" - "sigs.k8s.io/controller-runtime/pkg/client" + k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) //go:generate mockgen -source=./infracluster.go -destination=./mock/infracluster_generated.go -package=mock type InfraCluster interface { - GenerateInfraClusterClient(infraClusterSecretRef *corev1.ObjectReference, ownerNamespace string, context gocontext.Context) (client.Client, string, error) + GenerateInfraClusterClient(infraClusterSecretRef *corev1.ObjectReference, ownerNamespace string, context gocontext.Context) (k8sclient.Client, string, error) } +// ClientFactoryFunc defines the function to create a new client +type ClientFactoryFunc func(config *rest.Config, options k8sclient.Options) (k8sclient.Client, error) + // New creates new InfraCluster instance -func New(client client.Client) InfraCluster { +func New(client k8sclient.Client) InfraCluster { + return NewWithFactory(client, k8sclient.New) +} + +// NewWithFactory creates new InfraCluster instance that uses the provided client factory function. +func NewWithFactory(client k8sclient.Client, factory ClientFactoryFunc) InfraCluster { return &infraCluster{ - Client: client, + Client: client, + ClientFactory: factory, } } type infraCluster struct { - client.Client + k8sclient.Client + ClientFactory ClientFactoryFunc } // GenerateInfraClusterClient creates a client for infra cluster. -func (w *infraCluster) GenerateInfraClusterClient(infraClusterSecretRef *corev1.ObjectReference, ownerNamespace string, context gocontext.Context) (client.Client, string, error) { +func (w *infraCluster) GenerateInfraClusterClient(infraClusterSecretRef *corev1.ObjectReference, ownerNamespace string, context gocontext.Context) (k8sclient.Client, string, error) { if infraClusterSecretRef == nil { return w.Client, ownerNamespace, nil } infraKubeconfigSecret := &corev1.Secret{} - infraKubeconfigSecretKey := client.ObjectKey{Namespace: infraClusterSecretRef.Namespace, Name: infraClusterSecretRef.Name} + secretNamespace := infraClusterSecretRef.Namespace + if secretNamespace == "" { + secretNamespace = ownerNamespace + } + infraKubeconfigSecretKey := k8sclient.ObjectKey{Namespace: secretNamespace, Name: infraClusterSecretRef.Name} if err := w.Client.Get(context, infraKubeconfigSecretKey, infraKubeconfigSecret); err != nil { return nil, "", errors.Wrapf(err, "failed to fetch infra kubeconfig secret %s/%s", infraClusterSecretRef.Namespace, infraClusterSecretRef.Name) } kubeConfig, ok := infraKubeconfigSecret.Data["kubeconfig"] if !ok { - return nil, "", errors.New("Failed to retrieve infra kubeconfig from secret: 'kubeconfig' key is missing.") + return nil, "", errors.New("failed to retrieve infra kubeconfig from secret: 'kubeconfig' key is missing") } - namespace := "default" - namespaceBytes, ok := infraKubeconfigSecret.Data["namespace"] - if ok { + clientConfig, err := clientcmd.NewClientConfigFromBytes(kubeConfig) + if err != nil { + return nil, "", errors.Wrap(err, "failed to create K8s-API client config") + } + + namespace, _, err := clientConfig.Namespace() + if err != nil { + return nil, "", errors.Wrap(err, "failed to resolve namespace from client config") + } + if namespaceBytes, ok := infraKubeconfigSecret.Data["namespace"]; ok { namespace = string(namespaceBytes) namespace = strings.TrimSpace(namespace) } - // generate REST config - restConfig, err := clientcmd.RESTConfigFromKubeConfig(kubeConfig) + restConfig, err := clientConfig.ClientConfig() if err != nil { return nil, "", errors.Wrap(err, "failed to create REST config") } - // create the client - infraClusterClient, err := client.New(restConfig, client.Options{Scheme: w.Client.Scheme()}) + infraClusterClient, err := w.ClientFactory(restConfig, k8sclient.Options{Scheme: w.Client.Scheme()}) if err != nil { return nil, "", errors.Wrap(err, "failed to create infra cluster client") } diff --git a/pkg/infracluster/infracluster_test.go b/pkg/infracluster/infracluster_test.go new file mode 100644 index 000000000..a18541554 --- /dev/null +++ b/pkg/infracluster/infracluster_test.go @@ -0,0 +1,177 @@ +package infracluster_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/rest" + . "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/infracluster" + "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/testing" + "sigs.k8s.io/controller-runtime/pkg/client" + k8sclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +var ( + fakeClient client.Client + infraClusterSecret *corev1.Secret + ownerNamespace = "Mordor" + infraSecretName = "external-infra-kubeconfig" + kubeconfig = `apiVersion: v1 +clusters: +- cluster: + insecure-skip-tls-verify: true + server: https://gondor.com + name: gondor +contexts: +- context: + cluster: gondor + namespace: minastirith + user: aragorn + name: gondor +current-context: gondor +kind: Config +preferences: {} +users: +- name: aragorn +` +) + +var _ = Describe("InfraCluster", func() { + + It("should return the management client and namespace when the infrastructure secret reference is nil", func() { + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).Build() + + infraCluster := New(fakeClient) + infraClient, infraNamespace, err := infraCluster.GenerateInfraClusterClient(nil, ownerNamespace, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(infraClient).To(BeIdenticalTo(fakeClient)) + Expect(infraNamespace).To(Equal(ownerNamespace)) + }) + + It("should failed when the referenced infrastructure secret cannot be found", func() { + fakeClient := fake.NewFakeClientWithScheme(testing.SetupScheme()) + + infraClusterSecretRef := &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Secret", + Name: infraSecretName, + } + infraCluster := New(fakeClient) + + _, _, err := infraCluster.GenerateInfraClusterClient(infraClusterSecretRef, ownerNamespace, nil) + Expect(errors.IsNotFound(err)).To(BeTrue()) + }) + + It("should fail when the referenced infrastructure secret doesn't have a kubeconfig data in it", func() { + infraClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: infraSecretName, + Namespace: ownerNamespace, + }, + Data: map[string][]byte{}, + } + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(infraClusterSecret).Build() + + infraClusterSecretRef := &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Secret", + Name: infraSecretName, + } + + infraCluster := New(fakeClient) + _, _, err := infraCluster.GenerateInfraClusterClient(infraClusterSecretRef, ownerNamespace, nil) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(Equal("failed to retrieve infra kubeconfig from secret: 'kubeconfig' key is missing")) + }) + + It("should fail when the referenced infrastructure secret kubeconfig data is invalid", func() { + infraClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: infraSecretName, + Namespace: ownerNamespace, + }, + Data: map[string][]byte{ + "kubeconfig": []byte("hello world"), + }, + } + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(infraClusterSecret).Build() + + infraClusterSecretRef := &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Secret", + Name: infraSecretName, + } + + infraCluster := New(fakeClient) + _, _, err := infraCluster.GenerateInfraClusterClient(infraClusterSecretRef, ownerNamespace, nil) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to create K8s-API client config")) + }) + + It("should return the infra-client and the namespace defined in the secret, when set", func() { + + infraClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: infraSecretName, + Namespace: ownerNamespace, + }, + Data: map[string][]byte{ + "kubeconfig": []byte(kubeconfig), + "namespace": []byte("Shire"), + }, + } + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(infraClusterSecret).Build() + + infraClusterSecretRef := &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Secret", + Name: infraSecretName, + } + + fakeInfraClient := fake.NewFakeClient() + infraCluster := NewWithFactory(fakeClient, + func(config *rest.Config, options k8sclient.Options) (k8sclient.Client, error) { + return fakeInfraClient, nil + }, + ) + infraClient, namespace, err := infraCluster.GenerateInfraClusterClient(infraClusterSecretRef, ownerNamespace, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(infraClient).To(BeIdenticalTo(fakeInfraClient)) + Expect(namespace).To(Equal("Shire")) + }) + + It("should return the infra-client and kubeconfig namespace when the secret doesn't specified one", func() { + + infraClusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: infraSecretName, + Namespace: ownerNamespace, + }, + Data: map[string][]byte{ + "kubeconfig": []byte(kubeconfig), + }, + } + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(infraClusterSecret).Build() + + infraClusterSecretRef := &corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Secret", + Name: infraSecretName, + } + + fakeInfraClient := fake.NewFakeClient() + infraCluster := NewWithFactory(fakeClient, + func(config *rest.Config, options k8sclient.Options) (k8sclient.Client, error) { + return fakeInfraClient, nil + }, + ) + infraClient, namespace, err := infraCluster.GenerateInfraClusterClient(infraClusterSecretRef, ownerNamespace, nil) + Expect(err).NotTo(HaveOccurred()) + Expect(infraClient).To(BeIdenticalTo(fakeInfraClient)) + Expect(namespace).To(Equal("minastirith")) + }) + +}) diff --git a/pkg/infracluster/kubevirt_suite_test.go b/pkg/infracluster/kubevirt_suite_test.go new file mode 100644 index 000000000..1cad8833a --- /dev/null +++ b/pkg/infracluster/kubevirt_suite_test.go @@ -0,0 +1,13 @@ +package infracluster_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestKubevirt(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "InfraCluster Suite") +} diff --git a/pkg/kubevirt/machine.go b/pkg/kubevirt/machine.go index bb5206231..38bcc443a 100644 --- a/pkg/kubevirt/machine.go +++ b/pkg/kubevirt/machine.go @@ -252,13 +252,14 @@ func (m *Machine) GenerateProviderID() (string, error) { // Delete deletes VM for this machine. func (m *Machine) Delete() error { - namespacedName := types.NamespacedName{Namespace: m.machineContext.KubevirtMachine.Namespace, Name: m.machineContext.KubevirtMachine.Name} + namespacedName := types.NamespacedName{Namespace: m.namespace, Name: m.machineContext.KubevirtMachine.Name} vm := &kubevirtv1.VirtualMachine{} if err := m.client.Get(m.machineContext.Context, namespacedName, vm); err != nil { if apierrors.IsNotFound(err) { m.machineContext.Logger.Info("VM does not exist, nothing to do.") return nil } + return errors.Wrapf(err, "failed to retrieve VM to delete") } if err := m.client.Delete(gocontext.Background(), vm); err != nil { diff --git a/pkg/kubevirt/machine_test.go b/pkg/kubevirt/machine_test.go index 35853f195..b2b6cdadf 100644 --- a/pkg/kubevirt/machine_test.go +++ b/pkg/kubevirt/machine_test.go @@ -26,14 +26,11 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" kubevirtv1 "kubevirt.io/api/core/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/log/zap" - infrav1 "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1" "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/context" "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/ssh" "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/testing" @@ -52,9 +49,6 @@ var ( kubevirtMachine = testing.NewKubevirtMachine(kubevirtMachineName, machineName) machine = testing.NewMachine(clusterName, machineName, kubevirtMachine) - virtualMachineInstance = testing.NewVirtualMachineInstance(kubevirtMachine) - virtualMachine = testing.NewVirtualMachine(virtualMachineInstance) - bootstrapDataSecret = testing.NewBootstrapDataSecret([]byte(fmt.Sprintf("#cloud-config\n\n%s\n", sshKey))) logger = zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)).WithName("machine_test") @@ -65,6 +59,9 @@ var ( var _ = Describe("Without KubeVirt VM running", func() { var machineContext *context.MachineContext + namespace := kubevirtMachine.Namespace + virtualMachineInstance := testing.NewVirtualMachineInstance(kubevirtMachine) + virtualMachine := testing.NewVirtualMachine(virtualMachineInstance) BeforeEach(func() { machineContext = &context.MachineContext{ @@ -84,7 +81,7 @@ var _ = Describe("Without KubeVirt VM running", func() { kubevirtMachine, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() fakeVMCommandExecutor = FakeVMCommandExecutor{false} }) @@ -92,7 +89,7 @@ var _ = Describe("Without KubeVirt VM running", func() { AfterEach(func() {}) It("NewMachine should have client and machineContext set, but vmiInstance equal nil", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.client).To(Equal(fakeClient)) Expect(externalMachine.machineContext).To(Equal(machineContext)) @@ -100,37 +97,37 @@ var _ = Describe("Without KubeVirt VM running", func() { }) It("Exists should return false", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.Exists()).To(BeFalse()) }) It("Address should return ''", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.Address()).To(Equal("")) }) It("IsReady should return false", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.IsReady()).To(BeFalse()) }) It("IsBootstrapped should return false", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.IsBootstrapped()).To(BeFalse()) }) It("SupportsCheckingIsBootstrapped should return false", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.SupportsCheckingIsBootstrapped()).To(BeFalse()) }) It("GenerateProviderID should fail", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) providerId, err := externalMachine.GenerateProviderID() Expect(err).To(HaveOccurred()) @@ -138,36 +135,48 @@ var _ = Describe("Without KubeVirt VM running", func() { }) It("Create should create VM, but not VMI", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) // read the vm before creation - validateVMNotExist(fakeClient, machineContext) + validateVMNotExist(virtualMachine, fakeClient, machineContext) err = externalMachine.Create(machineContext.Context) Expect(err).NotTo(HaveOccurred()) // read the vm before creation - validateVMExist(fakeClient, machineContext) + validateVMExist(virtualMachine, fakeClient, machineContext) }) It("Create should create VM if it doesn't exist", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte{}) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) Expect(err).NotTo(HaveOccurred()) // read the vm before creation - validateVMNotExist(fakeClient, machineContext) + validateVMNotExist(virtualMachine, fakeClient, machineContext) err = externalMachine.Create(machineContext.Context) Expect(err).NotTo(HaveOccurred()) // read the new created vm - validateVMExist(fakeClient, machineContext) + validateVMExist(virtualMachine, fakeClient, machineContext) + }) + + It("Delete should be lenient if VM doesn't exist", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) + Expect(err).NotTo(HaveOccurred()) + validateVMNotExist(virtualMachine, fakeClient, machineContext) + + err = externalMachine.Delete() + Expect(err).NotTo(HaveOccurred()) }) }) var _ = Describe("With KubeVirt VM running", func() { var machineContext *context.MachineContext + namespace := kubevirtMachine.Namespace + virtualMachineInstance := testing.NewVirtualMachineInstance(kubevirtMachine) + virtualMachine := testing.NewVirtualMachine(virtualMachineInstance) BeforeEach(func() { machineContext = &context.MachineContext{ @@ -195,7 +204,7 @@ var _ = Describe("With KubeVirt VM running", func() { virtualMachine, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() fakeVMCommandExecutor = FakeVMCommandExecutor{true} }) @@ -203,7 +212,7 @@ var _ = Describe("With KubeVirt VM running", func() { AfterEach(func() {}) It("NewMachine should have all client, machineContext and vmiInstance NOT nil", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.client).ToNot(BeNil()) Expect(externalMachine.machineContext).To(Equal(machineContext)) @@ -211,31 +220,31 @@ var _ = Describe("With KubeVirt VM running", func() { }) It("Exists should return true", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.Exists()).To(BeTrue()) }) It("Address should return non-empty IP", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.Address()).To(Equal(virtualMachineInstance.Status.Interfaces[0].IP)) }) It("IsReady should return true", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.IsReady()).To(BeTrue()) }) It("IsBootstrapped should return true", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.IsBootstrapped()).To(BeTrue()) }) It("SupportsCheckingIsBootstrapped should return true", func() { - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) Expect(externalMachine.SupportsCheckingIsBootstrapped()).To(BeTrue()) }) @@ -243,13 +252,22 @@ var _ = Describe("With KubeVirt VM running", func() { It("GenerateProviderID should succeed", func() { expectedProviderId := fmt.Sprintf("kubevirt://%s", kubevirtMachineName) - externalMachine, err := defaultTestMachine(machineContext, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) Expect(err).NotTo(HaveOccurred()) providerId, err := externalMachine.GenerateProviderID() Expect(err).ToNot(HaveOccurred()) Expect(providerId).To(Equal(expectedProviderId)) }) + It("Delete should succeed", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) + Expect(err).NotTo(HaveOccurred()) + validateVMExist(virtualMachine, fakeClient, machineContext) + + err = externalMachine.Delete() + Expect(err).NotTo(HaveOccurred()) + validateVMNotExist(virtualMachine, fakeClient, machineContext) + }) }) var _ = Describe("util functions", func() { @@ -298,40 +316,167 @@ var _ = Describe("util functions", func() { }) }) -func validateVMNotExist(fakeClient client.Client, machineContext *context.MachineContext) { +var _ = Describe("With KubeVirt VM running externally", func() { + var machineContext *context.MachineContext + namespace := "external" + virtualMachineInstance := testing.NewExternalVirtualMachineInstance(kubevirtMachine, namespace) + virtualMachine := testing.NewVirtualMachine(virtualMachineInstance) + + BeforeEach(func() { + machineContext = &context.MachineContext{ + Context: gocontext.TODO(), + Cluster: cluster, + KubevirtCluster: kubevirtCluster, + Machine: machine, + KubevirtMachine: kubevirtMachine, + BootstrapDataSecret: bootstrapDataSecret, + Logger: logger, + } + + virtualMachineInstance.Status.Conditions = []kubevirtv1.VirtualMachineInstanceCondition{ + { + Type: kubevirtv1.VirtualMachineInstanceReady, + Status: corev1.ConditionTrue, + }, + } + objects := []client.Object{ + cluster, + kubevirtCluster, + machine, + kubevirtMachine, + virtualMachineInstance, + virtualMachine, + } + + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() + + fakeVMCommandExecutor = FakeVMCommandExecutor{true} + }) + + AfterEach(func() {}) + + It("NewMachine should have all client, machineContext and vmiInstance NOT nil", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.client).ToNot(BeNil()) + Expect(externalMachine.machineContext).To(Equal(machineContext)) + Expect(externalMachine.vmiInstance).ToNot(BeNil()) + }) + + It("Exists should return true", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.Exists()).To(BeTrue()) + }) + + It("Address should return non-empty IP", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.Address()).To(Equal(virtualMachineInstance.Status.Interfaces[0].IP)) + }) + + It("IsReady should return true", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.IsReady()).To(BeTrue()) + }) + + It("IsBootstrapped should return true", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.IsBootstrapped()).To(BeTrue()) + }) + + It("SupportsCheckingIsBootstrapped should return true", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + Expect(externalMachine.SupportsCheckingIsBootstrapped()).To(BeTrue()) + }) + + It("GenerateProviderID should succeed", func() { + expectedProviderId := fmt.Sprintf("kubevirt://%s", kubevirtMachineName) + + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte(sshKey)) + Expect(err).NotTo(HaveOccurred()) + providerId, err := externalMachine.GenerateProviderID() + Expect(err).ToNot(HaveOccurred()) + Expect(providerId).To(Equal(expectedProviderId)) + }) + + It("Delete should succeed", func() { + externalMachine, err := defaultTestMachine(machineContext, namespace, fakeClient, fakeVMCommandExecutor, []byte{}) + Expect(err).NotTo(HaveOccurred()) + validateVMExist(virtualMachine, fakeClient, machineContext) + + err = externalMachine.Delete() + Expect(err).NotTo(HaveOccurred()) + validateVMNotExist(virtualMachine, fakeClient, machineContext) + }) +}) + +var _ = Describe("util functions", func() { + var machineContext *context.MachineContext + + BeforeEach(func() { + machineContext = &context.MachineContext{ + Context: gocontext.TODO(), + Cluster: cluster, + KubevirtCluster: kubevirtCluster, + Machine: machine, + KubevirtMachine: kubevirtMachine.DeepCopy(), + BootstrapDataSecret: bootstrapDataSecret, + Logger: logger, + } + }) + + It("GenerateProviderID should succeed", func() { + dataVolumeTemplates := []kubevirtv1.DataVolumeTemplateSpec{ + { + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"my": "label"}, + Annotations: map[string]string{"my": "annotation"}, + Name: "dv1", + }, + }, + } + volumes := []kubevirtv1.Volume{ + { + Name: "test1", + VolumeSource: kubevirtv1.VolumeSource{ + DataVolume: &kubevirtv1.DataVolumeSource{ + Name: "dv1", + }, + }, + }, + } + + machineContext.KubevirtMachine.Spec.VirtualMachineTemplate.Spec.DataVolumeTemplates = dataVolumeTemplates + machineContext.KubevirtMachine.Spec.VirtualMachineTemplate.Spec.Template.Spec.Volumes = volumes + + newVM := newVirtualMachineFromKubevirtMachine(machineContext, "default") + + Expect(newVM.Spec.DataVolumeTemplates[0].ObjectMeta.Name).To(Equal(kubevirtMachineName + "-dv1")) + Expect(newVM.Spec.Template.Spec.Volumes[0].VolumeSource.DataVolume.Name).To(Equal(kubevirtMachineName + "-dv1")) + }) +}) + +func validateVMNotExist(expected *kubevirtv1.VirtualMachine, fakeClient client.Client, machineContext *context.MachineContext) { vm := &kubevirtv1.VirtualMachine{} - key := client.ObjectKey{Name: virtualMachineInstance.Name, Namespace: virtualMachineInstance.Namespace} + key := client.ObjectKey{Name: expected.Name, Namespace: expected.Namespace} err := fakeClient.Get(machineContext.Context, key, vm) ExpectWithOffset(1, err).To(HaveOccurred()) ExpectWithOffset(1, apierrors.IsNotFound(err)).To(BeTrue()) } -func validateVMExist(fakeClient client.Client, machineContext *context.MachineContext) { +func validateVMExist(expected *kubevirtv1.VirtualMachine, fakeClient client.Client, machineContext *context.MachineContext) { vm := &kubevirtv1.VirtualMachine{} - key := client.ObjectKey{Name: virtualMachineInstance.Name, Namespace: virtualMachineInstance.Namespace} + key := client.ObjectKey{Name: expected.Name, Namespace: expected.Namespace} err := fakeClient.Get(machineContext.Context, key, vm) ExpectWithOffset(1, err).ToNot(HaveOccurred()) - Expect(vm.Name).To(Equal(virtualMachineInstance.Name)) - Expect(vm.Namespace).To(Equal(virtualMachineInstance.Namespace)) -} - -func setupScheme() *runtime.Scheme { - s := runtime.NewScheme() - if err := clusterv1.AddToScheme(s); err != nil { - panic(err) - } - if err := infrav1.AddToScheme(s); err != nil { - panic(err) - } - if err := kubevirtv1.AddToScheme(s); err != nil { - panic(err) - } - if err := corev1.AddToScheme(s); err != nil { - panic(err) - } - return s + Expect(vm.Name).To(Equal(expected.Name)) + Expect(vm.Namespace).To(Equal(expected.Namespace)) } type FakeVMCommandExecutor struct { @@ -354,9 +499,9 @@ func (e FakeVMCommandExecutor) ExecuteCommand(command string) (string, error) { } } -func defaultTestMachine(ctx *context.MachineContext, client client.Client, vmExecutor FakeVMCommandExecutor, sshPubKey []byte) (*Machine, error) { +func defaultTestMachine(ctx *context.MachineContext, namespace string, client client.Client, vmExecutor FakeVMCommandExecutor, sshPubKey []byte) (*Machine, error) { - machine, err := NewMachine(ctx, client, ctx.Cluster.Namespace, &ssh.ClusterNodeSshKeys{PublicKey: sshPubKey}) + machine, err := NewMachine(ctx, client, namespace, &ssh.ClusterNodeSshKeys{PublicKey: sshPubKey}) machine.getCommandExecutor = func(fake string, fakeKeys *ssh.ClusterNodeSshKeys) ssh.VMCommandExecutor { return vmExecutor diff --git a/pkg/loadbalancer/loadbalancer_test.go b/pkg/loadbalancer/loadbalancer_test.go index 34c040d9b..12109b01f 100644 --- a/pkg/loadbalancer/loadbalancer_test.go +++ b/pkg/loadbalancer/loadbalancer_test.go @@ -23,9 +23,6 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - kubevirtv1 "kubevirt.io/api/core/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -63,7 +60,7 @@ var _ = Describe("Load Balancer", func() { cluster, kubevirtCluster, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() }) It("should initialize load balancer without error", func() { @@ -93,7 +90,7 @@ var _ = Describe("Load Balancer", func() { kubevirtCluster, loadBalancerService, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() }) It("should initialize load balancer without error", func() { @@ -118,23 +115,6 @@ var _ = Describe("Load Balancer", func() { }) }) -func setupScheme() *runtime.Scheme { - s := runtime.NewScheme() - if err := clusterv1.AddToScheme(s); err != nil { - panic(err) - } - if err := infrav1.AddToScheme(s); err != nil { - panic(err) - } - if err := kubevirtv1.AddToScheme(s); err != nil { - panic(err) - } - if err := corev1.AddToScheme(s); err != nil { - panic(err) - } - return s -} - func newLoadBalancerService(kubevirtCluster *infrav1.KubevirtCluster) *corev1.Service { return &corev1.Service{ TypeMeta: metav1.TypeMeta{}, diff --git a/pkg/ssh/cluster_node_ssh_keys_test.go b/pkg/ssh/cluster_node_ssh_keys_test.go index aea30f0c2..c41b29056 100644 --- a/pkg/ssh/cluster_node_ssh_keys_test.go +++ b/pkg/ssh/cluster_node_ssh_keys_test.go @@ -6,9 +6,6 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - kubevirtv1 "kubevirt.io/api/core/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -43,7 +40,7 @@ var _ = Describe("ClusterNodeSshKeys", func() { cluster, kubevirtCluster, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() clusterNodeSshKeys = ssh.ClusterNodeSshKeys{ Client: fakeClient, ClusterContext: clusterContext, @@ -78,7 +75,7 @@ var _ = Describe("ClusterNodeSshKeys", func() { cluster, kubevirtCluster, } - fakeClient = fake.NewClientBuilder().WithScheme(setupScheme()).WithObjects(objects...).Build() + fakeClient = fake.NewClientBuilder().WithScheme(testing.SetupScheme()).WithObjects(objects...).Build() clusterNodeSshKeys = ssh.ClusterNodeSshKeys{ Client: fakeClient, ClusterContext: clusterContext, @@ -108,20 +105,3 @@ var _ = Describe("ClusterNodeSshKeys", func() { }) }) }) - -func setupScheme() *runtime.Scheme { - s := runtime.NewScheme() - if err := clusterv1.AddToScheme(s); err != nil { - panic(err) - } - if err := infrav1.AddToScheme(s); err != nil { - panic(err) - } - if err := kubevirtv1.AddToScheme(s); err != nil { - panic(err) - } - if err := corev1.AddToScheme(s); err != nil { - panic(err) - } - return s -} diff --git a/pkg/testing/common.go b/pkg/testing/common.go index c107b4fa8..f76a2bff2 100644 --- a/pkg/testing/common.go +++ b/pkg/testing/common.go @@ -3,6 +3,7 @@ package testing import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" kubevirtv1 "kubevirt.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -114,6 +115,26 @@ func NewVirtualMachineInstance(kubevirtMachine *infrav1.KubevirtMachine) *kubevi } } +// NewExternalVirtualMachineInstance instantiates a new external VirtualMachineInstance; i.e. one in a specified +// namespace that might differ from the kubevirtMachine one. +func NewExternalVirtualMachineInstance(kubevirtMachine *infrav1.KubevirtMachine, namespace string) *kubevirtv1.VirtualMachineInstance { + return &kubevirtv1.VirtualMachineInstance{ + TypeMeta: metav1.TypeMeta{ + Kind: "VirtualMachineInstance", + APIVersion: "kubevirt.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: kubevirtMachine.Name, + Namespace: namespace, + }, + Status: kubevirtv1.VirtualMachineInstanceStatus{ + Interfaces: []kubevirtv1.VirtualMachineInstanceNetworkInterface{ + {IP: "1.1.1.1"}, + }, + }, + } +} + func NewVirtualMachine(vmi *kubevirtv1.VirtualMachineInstance) *kubevirtv1.VirtualMachine { return &kubevirtv1.VirtualMachine{ TypeMeta: metav1.TypeMeta{ @@ -133,3 +154,21 @@ func NewBootstrapDataSecret(userData []byte) *corev1.Secret { s.Data["userdata"] = userData return s } + +// SetupScheme setups the scheme for a fake client. +func SetupScheme() *runtime.Scheme { + s := runtime.NewScheme() + if err := clusterv1.AddToScheme(s); err != nil { + panic(err) + } + if err := infrav1.AddToScheme(s); err != nil { + panic(err) + } + if err := kubevirtv1.AddToScheme(s); err != nil { + panic(err) + } + if err := corev1.AddToScheme(s); err != nil { + panic(err) + } + return s +} diff --git a/pkg/workloadcluster/mock/workloadcluster_generated.go b/pkg/workloadcluster/mock/workloadcluster_generated.go index 53b63e9dc..3a7bc1345 100644 --- a/pkg/workloadcluster/mock/workloadcluster_generated.go +++ b/pkg/workloadcluster/mock/workloadcluster_generated.go @@ -8,9 +8,9 @@ import ( reflect "reflect" gomock "github.com/golang/mock/gomock" - client "sigs.k8s.io/controller-runtime/pkg/client" - + kubernetes "k8s.io/client-go/kubernetes" context "sigs.k8s.io/cluster-api-provider-kubevirt/pkg/context" + client "sigs.k8s.io/controller-runtime/pkg/client" ) // MockWorkloadCluster is a mock of WorkloadCluster interface. @@ -50,3 +50,18 @@ func (mr *MockWorkloadClusterMockRecorder) GenerateWorkloadClusterClient(ctx int mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateWorkloadClusterClient", reflect.TypeOf((*MockWorkloadCluster)(nil).GenerateWorkloadClusterClient), ctx) } + +// GenerateWorkloadClusterK8sClient mocks base method. +func (m *MockWorkloadCluster) GenerateWorkloadClusterK8sClient(ctx *context.MachineContext) (kubernetes.Interface, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GenerateWorkloadClusterK8sClient", ctx) + ret0, _ := ret[0].(kubernetes.Interface) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GenerateWorkloadClusterK8sClient indicates an expected call of GenerateWorkloadClusterK8sClient. +func (mr *MockWorkloadClusterMockRecorder) GenerateWorkloadClusterK8sClient(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GenerateWorkloadClusterK8sClient", reflect.TypeOf((*MockWorkloadCluster)(nil).GenerateWorkloadClusterK8sClient), ctx) +} diff --git a/pkg/workloadcluster/workloadcluster.go b/pkg/workloadcluster/workloadcluster.go index c1ae0e38c..0fd9f21b8 100644 --- a/pkg/workloadcluster/workloadcluster.go +++ b/pkg/workloadcluster/workloadcluster.go @@ -3,6 +3,7 @@ package workloadcluster import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" + k8sclient "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" @@ -12,6 +13,7 @@ import ( //go:generate mockgen -source=./workloadcluster.go -destination=./mock/workloadcluster_generated.go -package=mock type WorkloadCluster interface { GenerateWorkloadClusterClient(ctx *context.MachineContext) (client.Client, error) + GenerateWorkloadClusterK8sClient(ctx *context.MachineContext) (k8sclient.Interface, error) } func New(client client.Client) WorkloadCluster { @@ -48,6 +50,29 @@ func (w *workloadCluster) GenerateWorkloadClusterClient(ctx *context.MachineCont return workloadClusterClient, nil } +// GenerateWorkloadClusterK8sClient creates a kubernetes client for workload cluster. +func (w *workloadCluster) GenerateWorkloadClusterK8sClient(ctx *context.MachineContext) (k8sclient.Interface, error) { + // get workload cluster kubeconfig + kubeConfig, err := w.getKubeconfigForWorkloadCluster(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to get kubeconfig for workload cluster") + } + + // generate REST config + restConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(kubeConfig)) + if err != nil { + return nil, errors.Wrap(err, "failed to create REST config") + } + + // create the client + workloadClusterClient, err := k8sclient.NewForConfig(restConfig) + if err != nil { + return nil, errors.Wrap(err, "failed to create workload cluster client") + } + + return workloadClusterClient, nil +} + // getKubeconfigForWorkloadCluster fetches kubeconfig for workload cluster from the corresponding secret. func (w *workloadCluster) getKubeconfigForWorkloadCluster(ctx *context.MachineContext) (string, error) { // workload cluster kubeconfig can be found in a secret with suffix "-kubeconfig" diff --git a/templates/cluster-template-ext-infra.yaml b/templates/cluster-template-ext-infra.yaml index 029a74b55..c9d457256 100644 --- a/templates/cluster-template-ext-infra.yaml +++ b/templates/cluster-template-ext-infra.yaml @@ -8,10 +8,10 @@ spec: clusterNetwork: pods: cidrBlocks: - - 10.244.0.0/16 + - 10.243.0.0/16 services: cidrBlocks: - - 10.96.0.0/12 + - 10.95.0.0/16 infrastructureRef: apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 kind: KubevirtCluster @@ -58,6 +58,7 @@ spec: - disk: bus: virtio name: containervolume + evictionStrategy: External volumes: - containerDisk: image: "${NODE_VM_IMAGE_TEMPLATE}" @@ -79,6 +80,10 @@ spec: kubeadmConfigSpec: clusterConfiguration: imageRepository: ${IMAGE_REPO} + networking: + dnsDomain: "${CLUSTER_NAME}.${NAMESPACE}.local" + podSubnet: 10.243.0.0/16 + serviceSubnet: 10.95.0.0/16 initConfiguration: nodeRegistration: criSocket: "${CRI_PATH}" @@ -110,6 +115,7 @@ spec: - disk: bus: virtio name: containervolume + evictionStrategy: External volumes: - containerDisk: image: "${NODE_VM_IMAGE_TEMPLATE}" diff --git a/templates/cluster-template-persistent-storage.yaml b/templates/cluster-template-persistent-storage.yaml index 8889085f2..fc0d6407e 100644 --- a/templates/cluster-template-persistent-storage.yaml +++ b/templates/cluster-template-persistent-storage.yaml @@ -8,10 +8,10 @@ spec: clusterNetwork: pods: cidrBlocks: - - 10.244.0.0/16 + - 10.243.0.0/16 services: cidrBlocks: - - 10.96.0.0/12 + - 10.95.0.0/16 infrastructureRef: apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 kind: KubevirtCluster @@ -68,6 +68,7 @@ spec: - disk: bus: virtio name: dv-volume + evictionStrategy: External volumes: - dataVolume: name: "${CLUSTER_NAME}-boot-volume" @@ -89,6 +90,10 @@ spec: kubeadmConfigSpec: clusterConfiguration: imageRepository: ${IMAGE_REPO} + networking: + dnsDomain: "${CLUSTER_NAME}.${NAMESPACE}.local" + podSubnet: 10.243.0.0/16 + serviceSubnet: 10.95.0.0/16 initConfiguration: nodeRegistration: criSocket: "${CRI_PATH}" @@ -136,6 +141,7 @@ spec: - disk: bus: virtio name: dv-volume + evictionStrategy: External volumes: - dataVolume: name: "${CLUSTER_NAME}-boot-volume" diff --git a/templates/cluster-template.yaml b/templates/cluster-template.yaml index 782d1bd3c..fc29f8418 100644 --- a/templates/cluster-template.yaml +++ b/templates/cluster-template.yaml @@ -8,10 +8,10 @@ spec: clusterNetwork: pods: cidrBlocks: - - 10.244.0.0/16 + - 10.243.0.0/16 services: cidrBlocks: - - 10.96.0.0/12 + - 10.95.0.0/16 infrastructureRef: apiVersion: infrastructure.cluster.x-k8s.io/v1alpha1 kind: KubevirtCluster @@ -58,6 +58,7 @@ spec: - disk: bus: virtio name: containervolume + evictionStrategy: External volumes: - containerDisk: image: "${NODE_VM_IMAGE_TEMPLATE}" @@ -79,6 +80,10 @@ spec: kubeadmConfigSpec: clusterConfiguration: imageRepository: ${IMAGE_REPO} + networking: + dnsDomain: "${CLUSTER_NAME}.${NAMESPACE}.local" + podSubnet: 10.243.0.0/16 + serviceSubnet: 10.95.0.0/16 initConfiguration: nodeRegistration: criSocket: "${CRI_PATH}" @@ -112,6 +117,7 @@ spec: - disk: bus: virtio name: containervolume + evictionStrategy: External volumes: - containerDisk: image: "${NODE_VM_IMAGE_TEMPLATE}"