From 3dcccd947c666fbfbd2821ebeeecf3ed9be4ad91 Mon Sep 17 00:00:00 2001 From: Gaurav Mehta Date: Mon, 6 Nov 2023 22:03:51 +1100 Subject: [PATCH] initial baseline changes to update dependencies staging changes for template and workflow support changes up cloud-config generation and updated tests workflow reconcile cleanup changes for cloud-init config changes for cloud-init config fixed up event recording for cluster to workflow mapping moved workflow and template reconcile to a different controller updated workflow support setup endpoint svc to disable hardware ipxe to avoid ipxe loop added support for ipxe + iso based provisioning add BOOTIF to kernel arguments to ensure boot from correct interface only change to how configurl is processed and change or priority staging inventory and tinkerbell ipxe and cloud-init changes working ipxe boot for arm / amd instances working baseline for iso based installs fix arch lookup for hardware updated seeder chart and added a custom tinkerbell chart working baseline of minimal tinkerbell chart without lb added logic to lookup smee pod when deployed using local tinkerbell chart update netip dependency clean up inventory status when freed and fix up tink hardware generation tidy up golangci-lint and how cluster/inventory reboot actions are performed add extra job to set ipxe bootoption fix ci failure minor changes to include rebase --- Dockerfile.dapper | 8 +- .../metal.harvesterhci.io_addresspools.yaml | 2 +- .../metal.harvesterhci.io_clusters.yaml | 14 +- .../metal.harvesterhci.io_inventories.yaml | 142 ++- chart/seeder/Chart.lock | 6 + chart/seeder/Chart.yaml | 15 +- chart/seeder/charts/boots/.helmignore | 23 - .../charts/boots/templates/_helpers.tpl | 62 -- .../charts/boots/templates/deployment.yaml | 90 -- .../charts/boots/templates/role-binding.yaml | 12 - chart/seeder/charts/boots/templates/role.yaml | 24 - .../charts/boots/templates/service.yaml | 15 - .../boots/templates/serviceaccount.yaml | 12 - chart/seeder/charts/boots/values.yaml | 60 -- chart/seeder/charts/rufio/.helmignore | 23 - .../charts/rufio/templates/_helpers.tpl | 62 -- .../charts/rufio/templates/deployment.yaml | 57 - .../charts/rufio/templates/role-binding.yaml | 12 - .../charts/rufio/templates/service.yaml | 15 - .../rufio/templates/serviceaccount.yaml | 12 - chart/seeder/charts/rufio/values.yaml | 42 - chart/seeder/templates/_helpers.tpl | 20 - chart/seeder/templates/deployment.yaml | 10 +- chart/seeder/templates/rbac.yaml | 175 ++-- chart/seeder/templates/service.yaml | 22 +- chart/seeder/values.yaml | 36 +- chart/tinkerbell-stack/Chart.lock | 15 + chart/tinkerbell-stack/Chart.yaml | 38 + chart/tinkerbell-stack/README.md | 128 +++ chart/tinkerbell-stack/charts/hegel-0.3.3.tgz | Bin 0 -> 1390 bytes chart/tinkerbell-stack/charts/rufio-0.2.6.tgz | Bin 0 -> 4538 bytes chart/tinkerbell-stack/charts/smee-0.3.1.tgz | Bin 0 -> 4050 bytes chart/tinkerbell-stack/charts/tink-0.2.2.tgz | Bin 0 -> 4818 bytes .../dependency_charts/hegel/Chart.yaml | 24 + .../hegel/templates/deployment.yaml | 55 + .../hegel/templates/role.yaml | 26 + .../hegel/templates/rolebinding.yaml | 15 + .../hegel/templates/service-account.yaml | 7 + .../hegel/templates/service.yaml | 16 + .../dependency_charts/hegel/values.yaml | 23 + .../dependency_charts}/rufio/Chart.yaml | 4 +- .../rufio/crds/bmc.tinkerbell.org_jobs.yaml | 187 ++++ .../crds/bmc.tinkerbell.org_machines.yaml | 124 +++ .../rufio/crds/bmc.tinkerbell.org_tasks.yaml | 170 +++ .../rufio/templates/cluster-role-binding.yaml | 14 + .../rufio/templates/cluster-role.yaml} | 33 +- .../rufio/templates/deployment.yaml | 59 ++ .../leader-election-role-binding.yaml | 15 + .../rufio/templates/leader-election-role.yaml | 39 + .../rufio/templates/service-account.yaml | 7 + .../dependency_charts/rufio/values.yaml | 16 + .../dependency_charts/smee}/Chart.yaml | 6 +- .../smee/templates/_ports.tpl | 20 + .../smee/templates/cluster-role-binding.yaml | 14 + .../smee/templates/cluster-role.yaml | 25 + .../smee/templates/deployment.yaml | 92 ++ .../smee/templates/nginx-configmap.yaml | 52 + .../smee/templates/nginx-deploy.yaml | 87 ++ .../smee/templates/service-account.yaml | 7 + .../smee/templates/service.yaml | 29 + .../dependency_charts/smee/values.yaml | 131 +++ .../dependency_charts/tink/Chart.yaml | 24 + .../tink/crds/hardware-crd.yaml | 393 +++++++ .../tink/crds/template-crd.yaml | 68 ++ .../tink/crds/workflow-crd.yaml | 146 +++ .../tink/crds/workflow-data-crd.yaml | 139 +++ .../tink-controller/cluster-role-binding.yaml | 14 + .../tink-controller/cluster-role.yaml | 41 + .../templates/tink-controller/deployment.yaml | 37 + .../tink-controller/leader-election-role.yaml | 38 + .../leader-election-rolebinding.yaml | 15 + .../tink-controller/service-account.yaml | 7 + .../tink-server/cluster-role-binding.yaml | 14 + .../templates/tink-server/cluster-role.yaml | 36 + .../templates/tink-server/deployment.yaml | 47 + .../tink-server/service-account.yaml | 7 + .../tink/templates/tink-server/service.yaml | 16 + .../dependency_charts/tink/values.yaml | 39 + chart/tinkerbell-stack/docs/arch.md | 64 ++ chart/tinkerbell-stack/kubectl.go-template | 5 + chart/tinkerbell-stack/templates/hook.yaml | 56 + chart/tinkerbell-stack/values.yaml | 39 + go.mod | 140 +-- go.sum | 974 +++++++++++++++++- pkg/api/v1alpha1/cluster_types.go | 16 +- pkg/api/v1alpha1/common.go | 17 +- pkg/api/v1alpha1/inventory_types.go | 5 + pkg/api/v1alpha1/zz_generated.deepcopy.go | 7 + pkg/controllers/cluster_controller.go | 131 ++- pkg/controllers/cluster_controller_test.go | 77 +- .../cluster_events_controller_test.go | 2 +- .../cluster_tinkerbell_template_controller.go | 207 ++++ ...ter_tinkerbell_template_controller_test.go | 200 ++++ .../cluster_tinkerbell_workflow_controller.go | 165 +++ ...ter_tinkerbell_workflow_controller_test.go | 200 ++++ pkg/controllers/inventory_controller.go | 58 +- .../local_cluster_controller_test.go | 22 - pkg/controllers/local_node_controller_test.go | 4 - pkg/controllers/setup.go | 48 +- pkg/controllers/suite_test.go | 181 +++- pkg/controllers/testdata/config.yaml | 27 + pkg/controllers/workflow_controller.go | 114 ++ pkg/controllers/workflow_controller_test.go | 355 +++++++ pkg/endpoint/endpoint.go | 108 ++ pkg/endpoint/endpoint_test.go | 153 +++ pkg/mock/mock.go | 6 +- pkg/mock/workflow_controller.go | 54 + pkg/rufiojobwrapper/wrapper.go | 3 +- pkg/tink/template.go | 86 ++ pkg/tink/template_test.go | 46 + pkg/tink/testdata/create.yaml | 27 + pkg/tink/tink.go | 278 +++-- pkg/tink/tink_test.go | 288 ++++-- pkg/tink/types.go | 81 ++ pkg/util/client_test.go | 8 + pkg/util/inventory_test.go | 5 +- pkg/util/job.go | 10 +- scripts/ci | 3 +- scripts/quick | 6 + scripts/validate | 2 +- 120 files changed, 6709 insertions(+), 1099 deletions(-) create mode 100644 chart/seeder/Chart.lock delete mode 100644 chart/seeder/charts/boots/.helmignore delete mode 100644 chart/seeder/charts/boots/templates/_helpers.tpl delete mode 100644 chart/seeder/charts/boots/templates/deployment.yaml delete mode 100644 chart/seeder/charts/boots/templates/role-binding.yaml delete mode 100644 chart/seeder/charts/boots/templates/role.yaml delete mode 100644 chart/seeder/charts/boots/templates/service.yaml delete mode 100644 chart/seeder/charts/boots/templates/serviceaccount.yaml delete mode 100644 chart/seeder/charts/boots/values.yaml delete mode 100644 chart/seeder/charts/rufio/.helmignore delete mode 100644 chart/seeder/charts/rufio/templates/_helpers.tpl delete mode 100644 chart/seeder/charts/rufio/templates/deployment.yaml delete mode 100644 chart/seeder/charts/rufio/templates/role-binding.yaml delete mode 100644 chart/seeder/charts/rufio/templates/service.yaml delete mode 100644 chart/seeder/charts/rufio/templates/serviceaccount.yaml delete mode 100644 chart/seeder/charts/rufio/values.yaml create mode 100644 chart/tinkerbell-stack/Chart.lock create mode 100644 chart/tinkerbell-stack/Chart.yaml create mode 100644 chart/tinkerbell-stack/README.md create mode 100644 chart/tinkerbell-stack/charts/hegel-0.3.3.tgz create mode 100644 chart/tinkerbell-stack/charts/rufio-0.2.6.tgz create mode 100644 chart/tinkerbell-stack/charts/smee-0.3.1.tgz create mode 100644 chart/tinkerbell-stack/charts/tink-0.2.2.tgz create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/Chart.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/templates/deployment.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/templates/role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/templates/rolebinding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/templates/service-account.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/templates/service.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/hegel/values.yaml rename chart/{seeder/charts => tinkerbell-stack/dependency_charts}/rufio/Chart.yaml (96%) create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_jobs.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_machines.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_tasks.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role-binding.yaml rename chart/{seeder/charts/rufio/templates/role.yaml => tinkerbell-stack/dependency_charts/rufio/templates/cluster-role.yaml} (75%) create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/templates/deployment.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role-binding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/templates/service-account.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/rufio/values.yaml rename chart/{seeder/charts/boots => tinkerbell-stack/dependency_charts/smee}/Chart.yaml (95%) create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/_ports.tpl create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role-binding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/deployment.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-configmap.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-deploy.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/service-account.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/templates/service.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/smee/values.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/Chart.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/crds/hardware-crd.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/crds/template-crd.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-crd.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-data-crd.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role-binding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/deployment.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-rolebinding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/service-account.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role-binding.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/deployment.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service-account.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service.yaml create mode 100644 chart/tinkerbell-stack/dependency_charts/tink/values.yaml create mode 100644 chart/tinkerbell-stack/docs/arch.md create mode 100644 chart/tinkerbell-stack/kubectl.go-template create mode 100644 chart/tinkerbell-stack/templates/hook.yaml create mode 100644 chart/tinkerbell-stack/values.yaml create mode 100644 pkg/controllers/cluster_tinkerbell_template_controller.go create mode 100644 pkg/controllers/cluster_tinkerbell_template_controller_test.go create mode 100644 pkg/controllers/cluster_tinkerbell_workflow_controller.go create mode 100644 pkg/controllers/cluster_tinkerbell_workflow_controller_test.go create mode 100644 pkg/controllers/testdata/config.yaml create mode 100644 pkg/controllers/workflow_controller.go create mode 100644 pkg/controllers/workflow_controller_test.go create mode 100644 pkg/endpoint/endpoint.go create mode 100644 pkg/endpoint/endpoint_test.go create mode 100644 pkg/mock/workflow_controller.go create mode 100644 pkg/tink/template.go create mode 100644 pkg/tink/template_test.go create mode 100644 pkg/tink/testdata/create.yaml create mode 100644 pkg/tink/types.go create mode 100755 scripts/quick diff --git a/Dockerfile.dapper b/Dockerfile.dapper index 525ac84..121a2aa 100644 --- a/Dockerfile.dapper +++ b/Dockerfile.dapper @@ -3,21 +3,19 @@ FROM golang:1.22 ARG DAPPER_HOST_ARCH ENV ARCH $DAPPER_HOST_ARCH -RUN export K8S_VERSION=1.24.2 && \ +RUN export K8S_VERSION=1.28.0 && \ curl -sSLo envtest-bins.tar.gz "https://go.kubebuilder.io/test-tools/${K8S_VERSION}/$(go env GOOS)/$(go env GOARCH)" && \ mkdir /usr/local/kubebuilder && \ tar -C /usr/local/kubebuilder --strip-components=1 -zvxf envtest-bins.tar.gz && \ curl -sSLo kustomize.tar.gz "https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv4.5.7/kustomize_v4.5.7_linux_amd64.tar.gz" && \ tar -C /usr/bin --strip-components=1 -zxvf kustomize.tar.gz && \ - go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.15.0 + go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.2 RUN apt update && \ apt install -y bash git gcc docker.io vim less file curl wget ca-certificates qemu-utils ## install golangci -RUN if [ "${ARCH}" = "amd64" ]; then \ - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.57.1; \ - fi +RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.59.1 # The docker version in dapper is too old to have buildx. Install it manually. RUN curl -sSfL https://github.com/docker/buildx/releases/download/v0.13.1/buildx-v0.13.1.linux-${ARCH} -o buildx-v0.13.1.linux-${ARCH} && \ diff --git a/chart/seeder-crd/templates/metal.harvesterhci.io_addresspools.yaml b/chart/seeder-crd/templates/metal.harvesterhci.io_addresspools.yaml index e261eb6..c81ca96 100644 --- a/chart/seeder-crd/templates/metal.harvesterhci.io_addresspools.yaml +++ b/chart/seeder-crd/templates/metal.harvesterhci.io_addresspools.yaml @@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - {} + controller-gen.kubebuilder.io/version: v0.6.1 creationTimestamp: null name: addresspools.metal.harvesterhci.io spec: diff --git a/chart/seeder-crd/templates/metal.harvesterhci.io_clusters.yaml b/chart/seeder-crd/templates/metal.harvesterhci.io_clusters.yaml index edb17b2..72ed2a4 100644 --- a/chart/seeder-crd/templates/metal.harvesterhci.io_clusters.yaml +++ b/chart/seeder-crd/templates/metal.harvesterhci.io_clusters.yaml @@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - {} + controller-gen.kubebuilder.io/version: v0.6.1 creationTimestamp: null name: clusters.metal.harvesterhci.io spec: @@ -48,8 +48,14 @@ spec: properties: clusterConfig: properties: + bondOptions: + additionalProperties: + type: string + type: object configURL: type: string + customProvisioningTemplate: + type: string nameservers: items: type: string @@ -58,6 +64,12 @@ spec: items: type: string type: array + streamImageMode: + type: boolean + vlanID: + type: integer + wipeDisks: + type: boolean type: object imageURL: type: string diff --git a/chart/seeder-crd/templates/metal.harvesterhci.io_inventories.yaml b/chart/seeder-crd/templates/metal.harvesterhci.io_inventories.yaml index 3b0c3ca..c49a93f 100644 --- a/chart/seeder-crd/templates/metal.harvesterhci.io_inventories.yaml +++ b/chart/seeder-crd/templates/metal.harvesterhci.io_inventories.yaml @@ -4,7 +4,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - {} + controller-gen.kubebuilder.io/version: v0.6.1 creationTimestamp: null name: inventories.metal.harvesterhci.io spec: @@ -47,7 +47,7 @@ spec: description: InventorySpec defines the desired state of Inventory properties: baseboardSpec: - description: MachineSpec defines desired machine state + description: MachineSpec defines desired machine state. properties: connection: description: Connection contains connection data for a Baseboard @@ -56,7 +56,8 @@ spec: authSecretRef: description: AuthSecretRef is the SecretReference that contains authentication information of the Machine. The Secret must - contain username and password keys. + contain username and password keys. This is optional as + it is not required when using the RPC provider. properties: name: description: name is unique within a namespace to reference @@ -80,11 +81,142 @@ spec: description: Port is the port number for connecting with the Machine. type: integer + providerOptions: + description: ProviderOptions contains provider specific options. + properties: + intelAMT: + description: IntelAMT contains the options to customize + the IntelAMT provider. + properties: + port: + description: Port that intelAMT will use for calls. + type: integer + required: + - port + type: object + ipmitool: + description: IPMITOOL contains the options to customize + the Ipmitool provider. + properties: + cipherSuite: + description: CipherSuite that ipmitool will use for + calls. + type: string + port: + description: Port that ipmitool will use for calls. + type: integer + type: object + redfish: + description: Redfish contains the options to customize + the Redfish provider. + properties: + port: + description: Port that redfish will use for calls. + type: integer + required: + - port + type: object + rpc: + description: RPC contains the options to customize the + RPC provider. + properties: + consumerURL: + description: ConsumerURL is the URL where an rpc consumer/listener + is running and to which we will send and receive + all notifications. + type: string + experimental: + description: Experimental options. + properties: + customRequestPayload: + description: CustomRequestPayload must be in json. + type: string + dotPath: + description: 'DotPath is the path to the json + object where the bmclib RequestPayload{} struct + will be embedded. For example: object.data.body' + type: string + type: object + hmac: + description: HMAC is the options used to create a + HMAC signature. + properties: + prefixSigDisabled: + description: 'PrefixSigDisabled determines whether + the algorithm will be prefixed to the signature. + Example: sha256=abc123' + type: boolean + secrets: + description: Secrets are a map of algorithms to + secrets used for signing. + type: object + logNotificationsDisabled: + description: LogNotificationsDisabled determines whether + responses from rpc consumer/listeners will be logged + or not. + type: boolean + request: + description: Request is the options used to create + the rpc HTTP request. + properties: + httpContentType: + description: HTTPContentType is the content type + to use for the rpc request notification. + type: string + httpMethod: + description: HTTPMethod is the HTTP method to + use for the rpc request notification. + type: string + staticHeaders: + additionalProperties: + items: + type: string + type: array + description: StaticHeaders are predefined headers + that will be added to every request. + type: object + timestampFormat: + description: TimestampFormat is the time format + for the timestamp header. + type: string + timestampHeader: + description: 'TimestampHeader is the header name + that should contain the timestamp. Example: + X-BMCLIB-Timestamp' + type: string + type: object + signature: + description: Signature is the options used for adding + an HMAC signature to an HTTP request. + properties: + appendAlgoToHeaderDisabled: + description: 'AppendAlgoToHeaderDisabled decides + whether to append the algorithm to the signature + header or not. Example: X-BMCLIB-Signature becomes + X-BMCLIB-Signature-256 When set to true, a header + will be added for each algorithm. Example: X-BMCLIB-Signature-256 + and X-BMCLIB-Signature-512' + type: boolean + headerName: + description: 'HeaderName is the header name that + should contain the signature(s). Example: X-BMCLIB-Signature' + type: string + includedPayloadHeaders: + description: 'IncludedPayloadHeaders are headers + whose values will be included in the signature + payload. Example: X-BMCLIB-My-Custom-Header + All headers will be deduplicated.' + items: + type: string + type: array + type: object + required: + - consumerURL + type: object + type: object required: - - authSecretRef - host - insecureTLS - - port type: object required: - connection diff --git a/chart/seeder/Chart.lock b/chart/seeder/Chart.lock new file mode 100644 index 0000000..ebe9ca7 --- /dev/null +++ b/chart/seeder/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: stack + repository: file://dependency_charts/stack + version: 0.4.2 +digest: sha256:b6ffbeb6ddfd1c0c5ba12899dfae5d83bde1e07d89ac3e0189131a06ed348d53 +generated: "2024-03-20T16:37:55.441272+11:00" diff --git a/chart/seeder/Chart.yaml b/chart/seeder/Chart.yaml index 05e04d5..dc72ca3 100644 --- a/chart/seeder/Chart.yaml +++ b/chart/seeder/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 -name: seeder -description: A Helm chart for Kubernetes +name: harvester-seeder +description: A Helm chart for Harvester Seeder # A chart can be either an 'application' or a 'library' chart. # @@ -15,16 +15,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.0.1-dev # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: v0.1.0 -dependencies: - - name: boots - condition: subchartsEnabled - - name: rufio - condition: subchartsEnabled \ No newline at end of file +maintainers: + - name: harvester diff --git a/chart/seeder/charts/boots/.helmignore b/chart/seeder/charts/boots/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/chart/seeder/charts/boots/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/chart/seeder/charts/boots/templates/_helpers.tpl b/chart/seeder/charts/boots/templates/_helpers.tpl deleted file mode 100644 index 5329d02..0000000 --- a/chart/seeder/charts/boots/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "boots.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "boots.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "boots.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "boots.labels" -}} -helm.sh/chart: {{ include "boots.chart" . }} -{{ include "boots.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "boots.selectorLabels" -}} -app.kubernetes.io/name: {{ include "boots.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "boots.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "boots.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/chart/seeder/charts/boots/templates/deployment.yaml b/chart/seeder/charts/boots/templates/deployment.yaml deleted file mode 100644 index cad49bf..0000000 --- a/chart/seeder/charts/boots/templates/deployment.yaml +++ /dev/null @@ -1,90 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "boots.fullname" . }} - labels: - {{- include "boots.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - strategy: - type: Recreate - selector: - matchLabels: - {{- include "boots.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "boots.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "boots.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - - name: BOOTS_EXTRA_KERNEL_ARGS - value: tink_worker_image=quay.io/tinkerbell/tink-worker:latest - - name: DATA_MODEL_VERSION - value: kubernetes - - name: FACILITY_CODE - value: lab1 - - name: HTTP_BIND - value: 0.0.0.0:8080 - - name: PUBLIC_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: MIRROR_BASE_URL - value: "http://$(PUBLIC_IP):8080" - - name: PUBLIC_FQDN - value: "$(PUBLIC_IP):8080" - - name: TINKERBELL_GRPC_AUTHORITY - value: tink-server.tink-system:42113 - - name: TINKERBELL_TLS - value: "false" - args: - - -log-level - - debug - - -dhcp-addr - - 0.0.0.0:67 - ports: - - name: dhcp - containerPort: 67 - protocol: UDP - - name: tftp - containerPort: 69 - protocol: UDP - - name: syslog - containerPort: 514 - protocol: UDP - - name: http - containerPort: 8080 - protocol: TCP - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/chart/seeder/charts/boots/templates/role-binding.yaml b/chart/seeder/charts/boots/templates/role-binding.yaml deleted file mode 100644 index 1687785..0000000 --- a/chart/seeder/charts/boots/templates/role-binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "boots.fullname" . }}-role -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "boots.fullname" . }}-role -subjects: -- kind: ServiceAccount - name: {{ include "boots.fullname" . }} - namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/chart/seeder/charts/boots/templates/role.yaml b/chart/seeder/charts/boots/templates/role.yaml deleted file mode 100644 index 7f410bb..0000000 --- a/chart/seeder/charts/boots/templates/role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "boots.fullname" . }}-role -rules: -- apiGroups: - - tinkerbell.org - resources: - - hardware - - hardware/status - verbs: - - get - - list - - watch - - update -- apiGroups: - - tinkerbell.org - resources: - - workflows - - workflows/status - verbs: - - get - - list - - watch \ No newline at end of file diff --git a/chart/seeder/charts/boots/templates/service.yaml b/chart/seeder/charts/boots/templates/service.yaml deleted file mode 100644 index 5b0dead..0000000 --- a/chart/seeder/charts/boots/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "boots.fullname" . }} - labels: - {{- include "boots.labels" . | nindent 4 }} -spec: - type: ClusterIP - ports: - - port: 8080 - targetPort: http - protocol: TCP - name: http - selector: - {{- include "boots.selectorLabels" . | nindent 4 }} diff --git a/chart/seeder/charts/boots/templates/serviceaccount.yaml b/chart/seeder/charts/boots/templates/serviceaccount.yaml deleted file mode 100644 index 67c0802..0000000 --- a/chart/seeder/charts/boots/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "boots.serviceAccountName" . }} - labels: - {{- include "boots.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/chart/seeder/charts/boots/values.yaml b/chart/seeder/charts/boots/values.yaml deleted file mode 100644 index d56ec98..0000000 --- a/chart/seeder/charts/boots/values.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# Default values for boots. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: gmehta3/boots - pullPolicy: Always - # Overrides the image tag whose default is the chart appVersion. - tag: dev - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi -limits: - cpu: 500m - memory: 128Mi -requests: - cpu: 10m - memory: 64Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/chart/seeder/charts/rufio/.helmignore b/chart/seeder/charts/rufio/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/chart/seeder/charts/rufio/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/chart/seeder/charts/rufio/templates/_helpers.tpl b/chart/seeder/charts/rufio/templates/_helpers.tpl deleted file mode 100644 index dac674c..0000000 --- a/chart/seeder/charts/rufio/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "rufio.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "rufio.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "rufio.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "rufio.labels" -}} -helm.sh/chart: {{ include "rufio.chart" . }} -{{ include "rufio.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "rufio.selectorLabels" -}} -app.kubernetes.io/name: {{ include "rufio.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "rufio.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "rufio.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/chart/seeder/charts/rufio/templates/deployment.yaml b/chart/seeder/charts/rufio/templates/deployment.yaml deleted file mode 100644 index 7c35e6c..0000000 --- a/chart/seeder/charts/rufio/templates/deployment.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "rufio.fullname" . }} - labels: - {{- include "rufio.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - {{- include "rufio.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "rufio.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "rufio.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 8080 - protocol: TCP - - name: probe - containerPort: 8081 - protocol: TCP - - name: leader - containerPort: 9443 - protocol: TCP - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/chart/seeder/charts/rufio/templates/role-binding.yaml b/chart/seeder/charts/rufio/templates/role-binding.yaml deleted file mode 100644 index 2d8c021..0000000 --- a/chart/seeder/charts/rufio/templates/role-binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "rufio.fullname" . }}-manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "rufio.fullname" . }}-manager-role -subjects: -- kind: ServiceAccount - name: {{ include "rufio.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} \ No newline at end of file diff --git a/chart/seeder/charts/rufio/templates/service.yaml b/chart/seeder/charts/rufio/templates/service.yaml deleted file mode 100644 index 1ebdf42..0000000 --- a/chart/seeder/charts/rufio/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "rufio.fullname" . }} - labels: - {{- include "rufio.labels" . | nindent 4 }} -spec: - type: ClusterIP - ports: - - port: 9443 - targetPort: http - protocol: TCP - name: http - selector: - {{- include "rufio.selectorLabels" . | nindent 4 }} diff --git a/chart/seeder/charts/rufio/templates/serviceaccount.yaml b/chart/seeder/charts/rufio/templates/serviceaccount.yaml deleted file mode 100644 index 8fdc6f2..0000000 --- a/chart/seeder/charts/rufio/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "rufio.serviceAccountName" . }} - labels: - {{- include "rufio.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/chart/seeder/charts/rufio/values.yaml b/chart/seeder/charts/rufio/values.yaml deleted file mode 100644 index f86a144..0000000 --- a/chart/seeder/charts/rufio/values.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Default values for rufio. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: gmehta3/rufio - pullPolicy: Always - tag: dev - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/chart/seeder/templates/_helpers.tpl b/chart/seeder/templates/_helpers.tpl index f2d0471..5cc8773 100644 --- a/chart/seeder/templates/_helpers.tpl +++ b/chart/seeder/templates/_helpers.tpl @@ -59,24 +59,4 @@ Create the name of the service account to use {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} -{{- end }} - -{{- define "seeder.apiAffinity" }} -podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchExpressions: - - key: app.kubernetes.io/name - operator: In - values: - - seeder - topologyKey: kubernetes.io/hostname -nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/os - operator: In - values: - - linux {{- end }} \ No newline at end of file diff --git a/chart/seeder/templates/deployment.yaml b/chart/seeder/templates/deployment.yaml index 86d1c91..943d48b 100644 --- a/chart/seeder/templates/deployment.yaml +++ b/chart/seeder/templates/deployment.yaml @@ -26,7 +26,7 @@ spec: {{- end }} serviceAccountName: {{ include "seeder.serviceAccountName" . }} affinity: - {{ include "seeder.apiAffinity" . | indent 8 }} + {{- toYaml .Values.apiAffinity | nindent 8 }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: @@ -53,7 +53,13 @@ spec: protocol: TCP - name: leader containerPort: 9443 - protocol: TCP + protocol: TCP + - name: webhook + containerPort: 443 + protocol: TCP + - name: endpoint + containerPort: 9090 + protocol: TCP resources: {{- toYaml .Values.resources | nindent 12 }} {{- with .Values.nodeSelector }} diff --git a/chart/seeder/templates/rbac.yaml b/chart/seeder/templates/rbac.yaml index 83ce06a..2044bf5 100644 --- a/chart/seeder/templates/rbac.yaml +++ b/chart/seeder/templates/rbac.yaml @@ -2,159 +2,114 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: {{ include "seeder.fullname" . }}-manager-role rules: - apiGroups: - - apiextensions.k8s.io + - apiextensions.k8s.io resources: - - customresourcedefinitions - verbs: - - get - - list - - update - - watch - - create - - patch -- apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch -- apiGroups: - - bmc.tinkerbell.org - resources: - - machines - - jobs - - tasks - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - bmc.tinkerbell.org - resources: - - machines/status - - jobs/status - - tasks/status + - customresourcedefinitions verbs: - get + - list + - update + - watch - create - patch - - update - apiGroups: - - metal.harvesterhci.io - resources: - - addresspools - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - metal.harvesterhci.io - resources: - - addresspools/finalizers - verbs: - - update -- apiGroups: - - metal.harvesterhci.io + - "" resources: - - addresspools/status + - secrets verbs: - - get - - patch - - update + - get + - list + - watch + - create + - update - apiGroups: - - metal.harvesterhci.io + - "" resources: - - clusters + - configmaps + - services verbs: - - create - - delete - - get - - list - - patch - - update - - watch + - get + - list + - watch - apiGroups: - - metal.harvesterhci.io + - bmc.tinkerbell.org resources: - - clusters/finalizers + - machines + - jobs + - tasks verbs: - - update + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - - metal.harvesterhci.io + - bmc.tinkerbell.org resources: - - clusters/status + - machines/status + - jobs/status + - tasks/status verbs: - - get - - patch - - update + - get + - create + - patch + - update - apiGroups: - - metal.harvesterhci.io + - metal.harvesterhci.io resources: - - inventories + - '*' verbs: - - create - - delete - - get - - list - - patch - - update - - watch + - '*' - apiGroups: - - metal.harvesterhci.io + - tinkerbell.org resources: - - inventories/finalizers + - '*' verbs: - - update + - '*' - apiGroups: - - metal.harvesterhci.io + - "" resources: - - inventories/status + - nodes verbs: - - get - - patch - - update + - get + - list + - watch + - update + - patch - apiGroups: - - tinkerbell.org + - "" resources: - - hardware + - events verbs: - - create - - delete - - get - - list - - patch - - update - - watch + - create - apiGroups: - - "" + - admissionregistration.k8s.io resources: - - nodes + - validatingwebhookconfigurations verbs: - get - - list - watch + - list - update + - create + - delete - patch - apiGroups: - - "" + - apiregistration.k8s.io resources: - - events + - apiservices verbs: + - get + - watch + - list + - update - create + - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role diff --git a/chart/seeder/templates/service.yaml b/chart/seeder/templates/service.yaml index 7f4fc20..09ae1d1 100644 --- a/chart/seeder/templates/service.yaml +++ b/chart/seeder/templates/service.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "seeder.fullname" . }} + name: "harvester-seeder" labels: {{- include "seeder.labels" . | nindent 4 }} spec: @@ -11,5 +11,25 @@ spec: targetPort: http protocol: TCP name: http + - port: 443 + targetPort: webhook + protocol: TCP + name: webhook + selector: + {{- include "seeder.selectorLabels" . | nindent 4 }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "seeder.fullname" . }}-endpoint + labels: + {{- include "seeder.labels" . | nindent 4 }} +spec: + type: LoadBalancer + ports: + - port: 9090 + targetPort: endpoint + protocol: TCP + name: endpoint selector: {{- include "seeder.selectorLabels" . | nindent 4 }} diff --git a/chart/seeder/values.yaml b/chart/seeder/values.yaml index 0e256f4..5c45eb5 100644 --- a/chart/seeder/values.yaml +++ b/chart/seeder/values.yaml @@ -2,10 +2,10 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -replicaCount: 3 +replicaCount: 1 -image: - repository: rancher/harvester-seeder +image: + repository: gmehta3/harvester-seeder tag: dev pullPolicy: Always @@ -24,10 +24,12 @@ serviceAccount: podAnnotations: {} -podSecurityContext: {} +podSecurityContext: + {} # fsGroup: 2000 -securityContext: {} +securityContext: + {} # capabilities: # drop: # - ALL @@ -40,8 +42,8 @@ resources: cpu: "0.25" memory: "250Mi" limits: - cpu: "0.25" - memory: "250Mi" + cpu: "0.50" + memory: "500Mi" strategy: rollingUpdate: @@ -51,4 +53,22 @@ strategy: # set to true for use in harvester-addon embeddedMode: false -subchartsEnabled: true + +apiAffinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - seeder + topologyKey: kubernetes.io/hostname + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux diff --git a/chart/tinkerbell-stack/Chart.lock b/chart/tinkerbell-stack/Chart.lock new file mode 100644 index 0000000..6a8e964 --- /dev/null +++ b/chart/tinkerbell-stack/Chart.lock @@ -0,0 +1,15 @@ +dependencies: +- name: tink + repository: file://dependency_charts/tink + version: 0.2.2 +- name: smee + repository: file://dependency_charts/smee + version: 0.3.1 +- name: rufio + repository: file://dependency_charts/rufio + version: 0.2.6 +- name: hegel + repository: file://dependency_charts/hegel + version: 0.3.3 +digest: sha256:e4ed1bcaa46b187c718823b7596c5ff938206fef77bab6deb34ed395d0771770 +generated: "2024-03-20T20:03:04.620265+11:00" diff --git a/chart/tinkerbell-stack/Chart.yaml b/chart/tinkerbell-stack/Chart.yaml new file mode 100644 index 0000000..07a56eb --- /dev/null +++ b/chart/tinkerbell-stack/Chart.yaml @@ -0,0 +1,38 @@ +apiVersion: v2 +name: stack +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.4.2 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.4.2" + +dependencies: + - name: tink + version: "0.2.2" + repository: "file://dependency_charts/tink" + - name: smee + version: "0.3.1" + repository: "file://dependency_charts/smee" + - name: rufio + version: "0.2.6" + repository: "file://dependency_charts/rufio" + - name: hegel + version: "0.3.3" + repository: "file://dependency_charts/hegel" diff --git a/chart/tinkerbell-stack/README.md b/chart/tinkerbell-stack/README.md new file mode 100644 index 0000000..2c3b2bd --- /dev/null +++ b/chart/tinkerbell-stack/README.md @@ -0,0 +1,128 @@ +# Tinkerbell Stack + +This chart installs the full Tinkerbell stack. + +## TL;DR + +```bash +helm dependency build stack/ +trusted_proxies=$(kubectl get nodes -o go-template-file=stack/kubectl.go-template) +helm install stack-release stack/ --create-namespace --namespace tink-system --wait --set "smee.trustedProxies={${trusted_proxies}}" --set "hegel.trustedProxies={${trusted_proxies}}" +``` + +## Introduction + +This chart smeetraps a full Tinkerbell stack on a Kubernetes cluster using the Helm package manager. The Tinkerbell stack consists of the following components: + +- [Boots](https://github.com/tinkerbell/smee) +- [Hegel](https://github.com/tinkerbell/hegel) +- [Tink](https://github.com/tinkerbell/tink) +- [Rufio](https://github.com/tinkerbell/rufio) + +This chart also installs a load balancer ([kube-vip](https://kube-vip.io/)) in order to be able to provide a service type loadBalancer IP for the Tinkerbell stack services and an Nginx server for handling proxying to the Tinkerbell service and for serving the Hook artifacts. + +## Design details + +The stack chart does not use an ingress object and controller. This is because most ingress controllers do not support UDP. Boots uses UDP for DHCP, TFTP, and Syslog services. The ingress controllers that do support UDP require a lot of extra configuration, custom resources, etc. The stack chart deploys a very light weight Nginx deployment with a straightforward configuration that accommodates all the Tinkerbell stack services and serving Hook artifacts. + +## Prerequisites + +- Kubernetes 1.23+ +- Kubectl 1.23+ +- Helm 3.9.4+ + +## Installing the Chart + +Before installing the chart you'll want to customize the IP used for the load balancer (`stack.loadBalancerIP`). This IP provides ingress for Hegel, Tink, and Boots (TFTP, HTTP, and SYSLOG endpoints as well as unicast DHCP requests). + +Now, deploy the chart. + +```bash +helm dependency build stack/ +trusted_proxies=$(kubectl get nodes -o go-template-file=stack/kubectl.go-template) +helm install stack-release stack/ --create-namespace --namespace tink-system --wait --set "smee.trustedProxies={${trusted_proxies}}" --set "hegel.trustedProxies={${trusted_proxies}}" +``` + +These commands install the Tinkerbell Stack chart in the `tink-system` namespace with the release name of `stack-release`. + +## Uninstalling the Chart + +To uninstall/delete the `stack-release` deployment: + +```bash +helm uninstall stack-release --namespace tink-system +``` + +## Upgrading the Chart + +To upgrade the `stack-release` deployment: + +```bash +helm upgrade stack-release stack/ --namespace tink-system --wait +``` + +## Parameters + +### Stack Service Parameters + +| Name | Description | Value | +| ---- | ----------- | ----- | +| `stack.enabled` | Enable the deployment of the Tinkerbell stack chart | `true` | +| `stack.name` | Name for the stack chart | `tink-stack` | +| `stack.service.type` | Type of service to use for the Tinkerbell stack services. One of the [standard](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) Kubernetes service types. | `LoadBalancer` | +| `stack.selector` | Selector(s) to use for the mapping stack deployment with the service | `app: tink-stack` | +| `stack.loadBalancerIP` | Load balancer IP address to use for the Tinkerbell stack services | `192.168.2.111` | +| `stack.lbClass` | loadBalancerClass to use for in stack service | `kube-vip.io/kube-vip-class` | +| `stack.image` | Image to use for the proxying to Tinkerbell services and serving artifacts | `nginx:1.23.1` | +| `stack.hook.enabled` | Enable the deployment of the Hook artifacts | `true` | +| `stack.hook.name` | Name for the Hook artifacts server | `hook-files` | +| `stack.hook.port` | Port to use for the Hook artifacts server | `8080` | +| `stack.hook.image` | Image to use for downloading the Hook artifacts | `alpine` | +| `stack.hook.downloadsDest` | The directory on disk to where Hook artifacts will downloaded | `/opt/hook` | +| `stack.hook.downloadURL` | The base URL where all Hook tarballs and checksum.txt file exist for downloading | `https://github.com/tinkerbell/hook/releases/download/latest` | + +### Load Balancer Parameters (kube-vip) + +| Name | Description | Value | +| ---- | ----------- | ----- | +| `kubevip.enabled` | Enable the deployment of the kube-vip load balancer | `true` | +| `kubevip.name` | Name for the kube-vip load balancer service | `kube-vip` | +| `kubevip.image` | Image to use for the kube-vip load balancer | `ghcr.io/kube-vip/kube-vip:v0.5.0` | +| `kubevip.imagePullPolicy` | Image pull policy to use for kube-vip | `IfNotPresent` | +| `kubevip.roleName` | Role name to use for the kube-vip load service | `kube-vip-role` | +| `kubevip.roleBindingName` | Role binding name to use for the kube-vip load service | `kube-vip-rolebinding` | +| `kubevip.interface` | Interface to use for advertizing the load balancer IP. Leaving it unset to allow Kubevip to auto discover the interface to use. | `""` | + +### DHCP Relay Parameters + +| Name | Description | Value | +| ---- | ----------- | ----- | +| `stack.relay.name` | Name for the relay service | `dhcp-relay` | +| `stack.relay.enabled` | Enable the deployment of the DHCP relay service | `true` | +| `stack.relay.image` | Image to use for the DHCP relay service | `ghcr.io/jacobweinstock/dhcrelay` | +| `stack.relay.maxHopCount` | Maximum number of hops to allow for DHCP relay | `10` | +| `stack.relay.sourceInterface` | Host/Node interface to use for listening for DHCP broadcast packets | `eno1` | + +### Tinkerbell Services Parameters + +All dependent services(Boots, Hegel, Rufio, Tink) can have their values overridden here. The following format is used to accomplish this. + +```yaml +: + : + : + - : +``` + +Example: + +```yaml +hegel: + image: quay.io/tinkerbell/hegel:latest +``` + +### Boots Parameters + +| Name | Description | Value | +| ---- | ----------- | ----- | +| `smee.hostNetwork` | Whether to deploy Boots using `hostNetwork` on the pod spec. When `true` Boots will be able to receive DHCP broadcast messages. If `false`, Boots will be behind the load balancer VIP and will need to receive DHCP requests via unicast. | `true` | diff --git a/chart/tinkerbell-stack/charts/hegel-0.3.3.tgz b/chart/tinkerbell-stack/charts/hegel-0.3.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a79bcb7e54ac42a5a27665e9ddd3089d91e4e79e GIT binary patch literal 1390 zcmV-!1(Et6iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI;^Z`(E$&9i>RMcRiAs1(UxDFpPPYqKsun;B_VbQp$$mTqj; zG^vu5JumHlA4q+eQtUWQ-L%DgUt&`CQil@H(IGRzF|wm)6C!o6Br|sK6(S77aM0`7 zzhM}*|Ax_VbP)CW$AiJ~aVP8@gi)t+JUD>xYk+A-t~8Mc;TPYlJ-HtwNJihFR8;U7 z<{gh@S=|hSC<-DkMU_aJY1{Xd1LaB+o*>Lnlay!z3gw(8=y5W`80?Dj^fJR3NR~00 z5L4^TSL1eruJ^4cz7HD(|L26|sJ@l}Y~g=oez*AF@AUTkzmG^UV`3SDmU)xFbVkM) z!-t$K11gR*rBK80> zA$1J>FdP_tF$iYJb^A)uI$MGACt7EoL?v>WpfdT4&ZxG(0Fo@Xr8C=_;Y`S73{mIt zE9wDA{E(w+L^_W&kH zQj`H)OsE3A%xFRwTiUr%Y3{@r3`J`1pn!5aOu`H-8F;$DH!R@A@Ymm7!GDdjj1i6M zX!SOBrv_X2-!&imCja}rJ^$|~uC9Ebmk_)uz5vDRhfkk8*BFp2Q%Cd2n^K;}@Vs6k zUS$C+6Uhi!$u5#*Fg38hIgjbSB#WxsiH3#un|S#_UPsY%h|PcmZ= zz(?Ser^q!7niE_1G9N#{>>vhh2 zia7@BH) z2tUDlK{*^gI;>$gQ|k5qa}%LE;fM4QJVZW+_(?sAX|@WgIb2=Y>|*ga^x8BFn{1n# zve!Pt(o8t-&-ScIa-BpweRZu_SWjgW6$&Gv+OM%*qeE*tZo9hH-m+D3b`3$pwXDMR zFRQTbq#rpC*aOdFlJsyj5p~ zee191j~{LSXB_RW_kr8ae~!ED{a-IS?(hBIeZ;N&pB#}SAi16hN&mH{Il=U?GTXx1 z6rP)1l51J6DP*;;`h2e^b5_Wv4cseH%a1VWCzwOZ@LgvfM3Bwp({Qkv+z z@EmiLBd2DJy8dl8aCKv0Jmi<*SqM43WMZMN_uL)P9h7k$|H~ci&SYR4{|8Z<|NVYv z&;NUgUGl#?AlWVh&PmE0)Icyi$4fJK#l9O5dH{|`}3dsiCgi%W_gPYHxm7B=Q`g3CH_~j zf&V+*0&L@dzuRm3|H1zMzxNaC`R{KLfIA=j?(E#RKG5;Ye;GL=S8Lcky2+%_A`vWx wi)TaIqlp}&-gfk}@+i$?jCH03{o$WdHyG literal 0 HcmV?d00001 diff --git a/chart/tinkerbell-stack/charts/rufio-0.2.6.tgz b/chart/tinkerbell-stack/charts/rufio-0.2.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..fcc38f350b38e75bbb931b86d594558693d2627e GIT binary patch literal 4538 zcmV;r5k>AFiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PI{_a~n6Z&NF{Sm-oSEtIVq`DaAKMPO|daj>=N}l1iNdXPP7| z3@`>Tlo_A=_fxpcm2;sek+ye<7m_nTqtQS&8XvkTlQ|W`%O#O|uqF}vVGm_A8ja3g zzOsrGIA$~;rfF}LQ=JUXdS83k$Ks3A{}o{gs(l%NF8x0{Kdb8h+34)3|A#0c#!RfI zpk;z36{Znc;1oV3WIdo_s42fgIYY*V_Wg9_%!93VoiKJS7!B4_xSGEc`dXqwu6q)d zNMwL&+5?dIDM6*}cYq*HrZ65w_D6(~kn1U&y?jf10E|YoRPS_DsW_he_?Gq*$`uXp zA_zpn^}C$=ejvD(f-#i+h;Xt%*|RU+APG_a%rG!k>AhfBY{l%`KKj>vDH!&A`)XbP z*wtyE{S)OO<%_N^X0BSXr<#_<4$~HopMR(S8l#vIjcORML}}kk-*@v^yU?ZoryKfz zesc2isQ-s3U%vE#&SCJu?Euakz~6uOijIMtkzha)y%duEW%u*J-H*zch1IxsM|n7f zOSf(cYquAnCLz(p=&`dbU%q4=)vtBau~~WVac)|XnEon761Q;B1K41oqrbExmCQb3 zVC+oa)3_6;(_EU;8~WBnk)b(#Pi;21lm7Sn{YRL9lI{l*ZG&4Hq0%IZr@#}&w$xIYFtjR~8UyPW z^x@ev>rxc_i#{j}Bx=(jdl-k?hn>M1m#d_-zO? zWo9n|&4}+`sG6v|Z$qM%lf8)3QGSptzp4H9TPxN5-)#U9@+X7?JNEyR@pw|*|6iVt zkNf{2%2xhAiDQ-T^RKccQrhMjnIZFsb`r;>eVu2HGJrpt_hUvlPNC+cUgH?>ojh$7 zV_+Ck_P8yiV=giV;!T0uc7C_x*c7Ena5shAgjw@tF;F#yaStHXGtWptdX@{$g|@Cz z#u&g|GQ&W#!Ci*58mBA7IZ2qdI0vB|qiNYirRk1AdytBF9p~5 zS?5g1gkPw4g1;9+d&nv8-3}w;xbN3MwRaCo6-Hv86o;|_NmVQ7@5&O0BErL*+dd4d zy%V`m#R~lro|B8HNdN$ZF>!w_>54L3;Lj=`j5ut4PME^1CZj9lsMNI-Gb|EVY90TI zC7NLNyyX;zOC(G$|0=%{QcvN>(U0T8W6G(fguOyW);Aak9-0MuTBs4Dq$14TO-A`7 zA_?h(Su?HHyK>gT*tp18!BfcPm_vzav5;b6QDhAVuJ#~^lj6#N0`S<@%+)EkEQ6li z9HjLh%tO|&%0(SWx&@+PibfexZrA6pk_33YA^W3m^_`ch|5t}kKNbh>y#G0?;6Ibm z`RM%U{~e+{75=+5@Y{V=@^C+IN65GdD{i?d`j5knx6%JS-~Wt9CmZ)ale44#AEZ2` z{_mvtJ8Jv`P~kxEIbB2~-VPY9z-9$NEJv0+mbTG-AcPFP$CO)}3O{yO`{$)j6u3fO z#m5Wu9nqst_g_@1_TO(*ed2biCjkMw{J+WRxMKg$PR@?^{|6~s+5gPSR~(&Id;iV4 zJjYTfPX7ZLs^RAK%m029vnPlOY}fzE=86@Q|% zh~9gr;uX#xW4*ua#MN?P>R`p zEoML!=p}-yX9Ks*&sh{0w&CLXDr*``5u?PC?Z+B`DSdH?gxZFV-WlTnqvm3!V$pDS-s~5e=R7TQiY&Y)dbvg4&#&gLGpmPM0D+idfF;8Qlq-!S1Tn9r zXf{(Yi&dg;@xp1HSMS^$YC<^>qwh3?*Ehet8~!R9NZL^V2?A8gEwc!@egP^8mOxax z0&mQlK}0y6qtb)?iuRAmpY_rM_(e#-&m@W&zA(oMBk|0XSiuKqHzOmCj3V4qy`*ZBJ{()x5L%s4ng?gCJ2n);S`=3Wh=1x#q6JdKWm`+Kle+N2+vHVXO6jS@342{ ze!b*O>Lt;jC0#5~+TFUYSVL&c%RfO#BLOZ7BrIVwdoc!dPBGkI`j5$R5A4KAWC`rBK);S;5)bjCn~`2uef<_sCe^S)&l{$=XOEoj9}J z2*gC{*43Ks*tfsE`fchsGYe|L4Liot+o&+R^}7ATuEvcGC@mgrH*5w=!WWoYmw93= z`r!F4dc3)frln>(ts0K6wjpgfIO{fUF}QbyRo*(dO5}+Mlo?upu~tK|GN*jJAKnXj zNBN>}mS*3r0X4MF_V6F}W9P9rtYFIlIRxPVqcZ)d;ZB1}_tx$AvFA6=UG5+BqnryF8NM%?rQzifm~GcE>{~gR zuVd$HTC#(pYX(U55+z)Vdz6luTH->&ZyaxFgg*(PU!j9@ExDTd5&3+byY4WqsnYJ+ z8;7K}xBAKzp*C<@){jgt8Yn_hU#t{qgmyv9gwPOL!e9nLn#8cpI34qbR`dJH@Z6YG zb=PG@nI_rDIPjS0hrAbz?1@Q^WbzlmGKCSEjx_ zEy^VDbMKG)M#zamQ>jzFj=7l-3`x_eK;oywod24*>$k6lmQBr-IJY`mDR#k1H7IjY zX)X0e33O^M@+4{=_%p$qPG{!jeBS(4iFv&^?8`KrrT%rW4jRnAd20mHM7nd$uBg-r zVQ(>{0Soqpl>Gkw&DNTlHmKTZ z^T@lRE?!+Xp);<`&z2o@1;J8+jsjKAK`?uJiQ1fUs+OnQZ-I0(NhSC#=fE0 zFsZeRG4t%Z&PSQUzu`5x%OM~uLK&H{bZSV``KSolK3Cw*wA#(%0}cUQW-CIa$fD6F zEJOINZgFJGBqH3VXV@`$YCw5t|AeW<%!R1UkqXF6BpMh|8nh%_(YCF!(_Yl6NyBKo zw)ksG*D$r0uf;5%b9-OZIF1>@txV8Z#$O0ijSgKW>$bu+jNkfG)+VF7b=_uRTl|E+ zrTb8;+U%+-O{Ct!(%hu=nvIN?iiZjuOEAmw|E|H)S6!D4_sKwzKbaX|j*Ml4X_ z&n=2^KT$^HV6i{xb$)&PPs-;p0O%M1bPNFc8Ua9FKTAPCX#h|P@7Ytv*2hH7u>r=Z zo{fCPG(15S8XFJGnF#_vWl+xBHYg{*4SH}yPokGM_K%xt1D7^fzbMwvEL-}($C%h) zjdWxUuDI#gtONHCwRVLW|FRG)l;Xnn5bU~uC{Y>Z2EvIlMkYdQUSguuy^tZ?;ab(7 z3cBH}<~#ij@x1dfCJCpX67-=pK=P|}V<5XOimiD3-)UuLq8U8e0y^rr$*&!TW4E}I zxF>#0>BV>3Ap8*QY}lDIX2we95u@oqvX(+MK>MW;{!1vGE??6GuC9TEp+u$30oFV! z1|qfIQACu#LB7z-`g^y|F;Q;+vI1}4+-$-5RbD#_Wm4vdq%?+Lp5~^cVaa!0MA-j^ zXyC;D^T`y>CMVsjUJIEC+0X=@L^G7uwxvw+g$tf^M*V$q!%cG29r6*?JeGZx zcKp{~i9R|3v;+S=olIU<@!#>}i2oj>e2@6ATa^a`e{YGpt02GT(FW|B#}91gfa(es ztR2mR0l|jh1{B!7y12d?93kK%1YDB-5duB{1Z>o=I|ql_Jc#jxwiJv3J>)#&$<8}E!TcnLu6wW6XHe?`ekn7C!X*YHc%JO+cj!$>& z`K}p0-Nw8tyJs)CJ$uRQd4jy2&a9rDa(cGO+Sw||zdK{6Ghb&P**e|1I_=^3t$8{f z+goRj&Ym)KI`pnNJEtW#r!6z5B`>EnE2k|dr!6C=V?A!0jkB*@oQG!Oblbu9ESxRW zvpWN4*ZdopwVS<%X5VyW*mMrIOPw2YYqq!rdBBCRPT{T&3Y}NM_GG)wJ@9R{#{=iV z*d*$wON4Pb>c>o&Vmo+uN>dhXvvDolmb-TMAUE{mTq7siUkXTTKlU5=S9$2;L; YIhJENmP42S4*&rF|GCul0RV^q02KJ{X#fBK literal 0 HcmV?d00001 diff --git a/chart/tinkerbell-stack/charts/smee-0.3.1.tgz b/chart/tinkerbell-stack/charts/smee-0.3.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d445644db4281c3d936f91fbb5651250826ea3c4 GIT binary patch literal 4050 zcmV;@4=wN?iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PH;dZ`(Ms{aJs-!0Dn1P|1?(Bt3PzKrhYS=Iu6XB;8&Q_YMIq z(KgSNs3j>Ue%bu*5B$)lWjp;!w|8cN#wKTm!{N+u#2Hy6823+Rh)ZvY68h*%G~f6A zqv25h^?kqn*AI@49|gn1H}7vZMWav>3al;9AQLOF7o z;Sf-kQ4%4A=`1R$&%D6-+RNTG+qC^J5Y4gpVh&)7{T~kw{kHuN{iB`zKSbMuw`@A4 z7-F1JwoGs;flWZpFbK>SB*LC!hC+}$$BwfH=P1D~Ajk!d0SVn#Bc*%-pfm=G#+ZV@ z6i1SA;nlr`vj=Zy7)XMqmXKsXQJzLKO)p}pL?p%Bb2Ll{zvpP_5!RO^ont=6l=c;+ zaAAFx1{>v+ju<7;GK90qIg=xf1x{r#Uz#Ul%+*3N77H~e&r{FgSbHrILZBcouwXfl zuz)ek(^wdI+6GNvFSMF_PtW zP&NgM7no{4-&!hV(_hqB2tATcSg({Rme-8WAz?9Y?V@6=Mgsmm!>LxOryav^O(<2m zpvIg%m@y#>;+~_votrNqOb`{C=`0^p5}l3UT2YSigrqn&gvLz;JsSZ@^`{A=lwFf_ z3Y3|XN&wNCy#&NDq)Zl+LT3-+S(JG*DYLWD`%`aBQpA_Paq20Cp0-BKsacIGUA@G7 zfw@Prr=Z|GCJ1iflk7*vM<|-(qDM|-c9v-Y69Gi1rA%^amWe2Zx1|*n<|s7tJWo@# zv@xEMG&WLJ_INh(oI+S3^n$^$=X<^v=v{pM)5%Da!CY;}giLd;1>+gJCjw9kB*v*E z6N0%FY{Z!mwP*kml#+>3Ypp&RqH(Tu2{0?8CTyCo=&ITqRw$C_XERJ#s^TY%}$ z6@cd`2`N>^DH>B8TPFojxffS~H~=J5!H53mfF=~e(Xk#VB_2Yr=KvUq+b?1%D4UjF zi~TkB15heK2zz=k?DxM{`}sroy_)2QKFMyd1qKk&3@grh3ba>tD+D`%X@u;F#`nCi_wX~O>v~%la_noVvTi@tW;<-|8Nil&&=rzjuFR{2K8X$Lf>jZ-!BX~mUY2p93mi`{clHVzRoJW_j6vcgqex=Clo(4ysPG(Aa#I>z zlSiB`2xqB&8d@Mul<2qedy1kN;8gOZ+E9Fx;Yb?c&d>q_a`vhxEB){ebG)?6oa5!j z72aokD%34jxaaJ_=?zLUs?-X=wfgerA6KX6@2=jxy3pNV7zrU+y82U1G^go8OQvOQ zjw03zd~Y~Vde$Eddrmqf>5bJ1{W%Q0!J!v??dRnG)TZx$imey@D`n}zliBCI2-BY&xmgp)PvAyWM)u4vz62(ZOu;D-LM6G*kHKXdfz!L?IGV(Xh@@&J@4#3LH>n18@5c&AuIFdH< zH0YP+#`IMbu{@Rfk$#0nhCkrvi8-8i=IV~Oo3yT-Uy}Aq4Re;C%RChNrYzAtEczlgGUg_uy ziDWKx{{r)I4QGmF`I!oIHF7DpM zYdBl!o6O$5NgMDjR67#F#iQ6gr&*IxzW2Ok7Vu-|ZRV;s%&VXBt2B$+u=~u`Li5Nb znbtGo_g~OTKK-D5ilHnM)q(Z8^mL8$O4q4a$BeRUO&GW#Li~{UP-Hj?bp=RKa#BAi zZKokyRL&UA5_Ky4Qe$-!vpT6IQ8W*0N0{wbJ8(_ptVAp3sZbS&WdA@31rPp!l%z3E zB^)&&?CI29Us7YMcEA*no&qw+#X)3OS=$%YXk)?Kmb`w^_gePag+Fh@luHLFHnbS3 zdDdFZN=2Yi$YQfGO|t5n?JV;HwYb67L)C;}vN1IlS8Ac!z|~kC4e@DB)M_r5vZ<>p zf?n206qP`ATn#-|9yyKOc|OK&X%#QKjiQaL+>?vqm@D}96s9An zW7z&~B;{3HlHKUb5X6^m&eiHk8qqv%UhM71`VP)s#`U&&_=7F;8JGOY^Oc^xdp?r6 z6UN<4pPnnCshzCd;xXsCOR^Qz;>7R9Q|D?ImN{?X?k?1I6g4z_BRO(SLeW*asc`?z zND4jZ!M@F!H&26(tT^nK+N9jVl}RsNX*+oNolul)?l^{CLWCgc6k5s3O4O|ZIMDyv zE7p6uMVB?dHC=99v$v_$HL^pmEwxr!e*-D2Y@0|mlKd;A)WQ1^x>`T9R}@s|e@#xk zF1g41qu>7e%h}1*+2~+ZhP5E0Q+zd|uB2jRsWp5_#VWeVV7j)ZL7{i(OC!yxbjm2| z)0*ZqKsuDhTGke|v1yW;;;iIUR%v$Zvc+2G3hO$OsnDa2TPep#4Xui7vR(akQl++v zR`#V$tz!imV;%n*$rfd;Ald%*sjdrBO2}rKzdeB>xgjc04X2CdX=*~qQk83CHk1A% zXGz%T2AB{`V|z#1Y>oFgf|X&7IMSs`<`P23BaLY{E&4QFwAWmPz&h-zMYSs{F<_=n zp%bn{UN(A4ncN&fnc9>_q@qy^Csa>r?n8q46vI9kcVu&ZJ?NF8mFnujK`|%50sH|r z@Cyc8_ITsHF?3xQsa7u(FPbg_Z#)ZFM9)BbQI@wwUDS$iLNhQ;%x3xdb`A>o59Xmn zEV-~)#WPCdCjNY#Fu#FI^>3)P?*DYjjcY325|n+OOTaDn|AWKhXRZ6cqu_XV|NkJ( zl=Gec?d<$Loak+TgLJVWNdbYt8REJoj8F_?9HCrbAW}dy!_i#iiG3fzRI73_onj8T zevd?vaQ51zX3p(x$9<#Qx~i$t3I$6YNrg&RKk(Y6B%=s;ia-c|XeVSJ2QtngECd!1 zywLr4q3Z^3OJ`>RtMX$35cq?k0XI%D7nlQQOuleT6|t0ANy65aRum}_5~pzJ`$u+C z-D}@Ufqo5CSDoA}uLPD?rT`Y+yB8Qy_iO}@IZl|wS1RIqu^FXNP799>1d8LUo2yAN zq&~f9oECyn#rfmWudlDpU%ffKJiT~#dQpcFSi<8Oo??0xrvmgRZ{2ghCl--cROG7V zQtt)qL5gvVW2J?)N?BcbxlB<)B6xj%X_(3N`=u)@)#a7;jfjewuqEH(__}kp?2E1( zukaM%0kHHxVW;$iu-d5Fv(W=?*OX_G*)8=+?N-51*b@56X06?==l*kl>(&UI#@eq{ zt-hfZz*T~7uA*6<&LKz|B4$iNKNq|&W{6{RdiG~Bppg{@dxP_+_pdeC5!Z%~rZtb-myh?+^&Fn`wMy&r zst>oOEcfx??g{j*7M=3MDjgY>noO3E4f;tQ4>M&Ccq` z&DF0Dubr!UtFJv*dt~!mwfJZKWaW#0?YUY5Tb9Mxym(R4v=6%*Dt}C%Xzd>rsK~Cp z-3iu^&_6a%bS@ap6a0qdX>+?1)nhIcmD)9CMDedFT{aS$)yf-BZC%v5!l`cgAuh=T zMY1ThGQ6%hhmIMe;;}Nk4}Sne;-n=)7v^{wLZ<;i`Ce#;HMY3xT#3~yMZ#&5?6XYv z6;^G;91X7t*DiPYD?i~_8GfzpF4=aiqqX9Hs~#>g`tcz5fBxWE$Nk@~{{KPRz2g5e z^luf*Z!GlvxRR)y<9XQDZU3M5r@*$@e-QZX`v2kKv)%ij57J!M-Dv7xzc|vwHun7j zov|*TJ&G90{vJ!?H&_59;!|vcbKBK?TeB8~$p(RTQAoWKp-y!ZTs!_RrYe77p<}X+ z;*B-abwI9LoBjEt#!nu#gmc_Upm|xcZoj{_0`Jcc1ONa4 literal 0 HcmV?d00001 diff --git a/chart/tinkerbell-stack/charts/tink-0.2.2.tgz b/chart/tinkerbell-stack/charts/tink-0.2.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..bb61884d51a8b9cedf03b7dedd93fef4764be768 GIT binary patch literal 4818 zcmV;@5-sf?iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PH<$bK5wQ`K(`on!BotcS2c`WjUj&tEp^~n{iE&btT!{UU_pW zh=e4pNq_@@QZz~a`xXGcpP*j0r`R77lLQ)#Mt7sT@sPme?)>EnGSS~c&wX+X7z_r3 z$#|^(9}EWh{|Cd#xQ`z;D4EF@gl*Jpw&61yY`R zV(X(RfWGfy8_Jr!b%J!%ANB6L*BwNl^nVTA0P&+4fCl{^UQR}N{U47;o&KK!Y)S;9 zu8Y{T2Y`comu{y(umJS{NL1QN%Jl%i9$ca+_&tEzKBnig0Ah3Gy63sF)3r7tVU?S} zb#JJP?d=p?FWymc!w^SA^Z;N;84ErI!yW*TE%_AOepVki4VaC%qz?cWdsu{j17Q2X z6kHAlUij=GkFxC)3`fu3V)c%p-vh*RHHL)>ld&q#sEgi}b=vYEflI_JSt2a>S4((L&+ZsJZfbMFPsIN3HibV(X@1)@2%pc-L{2 z=&_CTVEB}YDHxB2!;6?E4-rxJRX?YCx@5k6&(fiJRWA{#GSN8Px5j5d*?)mN--QD4 zy#AisZooy@0W0i5>v^Kd|C@|1v-W>98eL5~`+o}f`qct>0s5b`3y=(bUn?Z|{=Jv> z5!oEteHe%pW%v)}+x73Bb7>;h!`>Yx&J?`VGLy1UJr4=!Kmn(*wEirtAd8*D5iTH09 z^W?#Y!d}Hsf$u<(Al`%@_aHV_zv7#RNbZKRyM;?Py!fVuTnD)*MaMqW-;bsIb3%jt zPrULyvI7nFe>58B{lCF@)cJoWfwuM^`aVxg{i|3!GM3(jbL57)4}HJcQ!?|X+IUmk zNA@%me^yL9;dk8vSCKPinsiTEn>VSx81^Porw~huF)BvQAT&e?K-3`>rcxpxCWxib zSW(Dcj!J!uaA_!n?lm=&Vp$y3;se=|XUpoOPOdV8WQok`%RWjHixh;DLBmT^r(Hu~ z;tNMFlVONJCP&{=0XE+*83i+RlZvH>9<{JOBqrj$9D zIIsWXVHf|M1akVXhyKWG|0&B5ws*2+|5SVX&etKT$F%{%3fZ&;Q7m zo&KK!j;H^|ivM8O{U6@a{=Kc22U+`nVzB-{xyr5o53epKgUp8pb+9%6Xu{cVy}!ii1Aq%?-%V5YH+(O7yTM|WuN}3TV2~vR{Xgirpbx$Q zf{BBO0F!Kqctv}^4F;ussP09ZepL44dA>|)b-sCLgW5Te+X-MyAZ_6zf=~`9WE3|&ZhcY7YDa)_&TM6rK)X9lrODTIU5fm5s ztF$p!@!etfO2mq}<35S1`upvXC}3^9KcX5#%e@gfeLbu@RWtt|B=`HoB>#Jv&;Jg_ zmtFqnB+zF5-zoRI*NonU4#$RO{onssaC81QfBye!aMAhyCxKf1w;Bw~S&AIgRk4NQn^n{}_oP3gbQ9DW{U$}F2X zhrJ4*UjHwyCi(q;!}0i{JO6bOuq-PV<74ziAR?c5F})jbLB02(OZy5fFv046kF+6x zgixWgq0S6j-yx(-5Z99K-Vgl#m%aq*a!m)I#xlaK6AW7BrfFng1 zX=*}FBPZ-1pbH>Ym;;788%O;PHE&wEes#V0kni>(~a_j@wk+Q!=OaO*#x+M6I z7&`}os%DkrB??&8*b?Xhbves30Eq)UxCIQ!c0fQ<7{mKpz*{PLOBQqrRzmoEdVapd zBGO`;dR{=V*q$qe#PdK<#?KwJM(#PsOA9i4g$1%jz|cALv89M7N|XDZ^B-|2`$LY} z61mZ!bg0$XNcEE90Yh}UZ^;nISCVV*Uw`-*=N;5A6~{%5NK%z2gCiM<$pSGwzzaq_ zg%uIUrOac(J4_+#x2j(bT0&)7_nt+$kL+(rIwj6tC21hDPRI;B#SEcF_=AIpH2*^XN zNJ;qX+n4XrB1(}->0-!L+AOsY%I_g<`ra0=Y~Ul_08CV;xOC)VHx)phF=Bo2QHqw7 zG$|DvInvHmQI~2L%(s9tdxf}QP>MmGM@@VJAhl(p^s52KB)qt}R!Aaqt>)F(TF1&a zM^Y&nS|Emqjhr%iHC!(;IHkr&nZgT5hzWideYDo_QC&9 z1|Zo2Dpp#>nPd5oiLDwx{w$`V5-ZmFErqtKJC%ABL7DN3Afq;s&68bG0!A0r+})KL zHIbW8qr#bx8WpP?o|=fY<@D%HI2E5HMJ1mqZI=Eq6K=u#m|QznZbDg7WJKcb1a` zi4A3UNz>tRoPd>kTN)(K_h$6UuC$MN0r>UhO_r`|BiGz8P={gdRo!=kan`V+T-51y zD`Z#>!0d47YWNHCJia#OFfit_1n4*n@y24toszJC9(K3QC>NA@P)wz8PsWA>NJUtp za!(*)LK^z+%*%kSw|XNS-isdzJ;CTx(`8dKc5)%qzRRSG|3>H@UDCPr&csf%E> zKMBCvg=B^+T{jIz4s?hQy4cadMkq~c`ugu2@P*TJ*V_iwjD>*90rQvLI7Jdov{hfhD<4y?)Nv$LnqZihQp{>#~a z?ynmLhJ+w7r&Jiu=dci1GnLCTYj9G` zoE_+H;Fcc-m(8}mK+cR&DrP?9d_(JJMWYci$=nzrs*hF7Q26_5ZI_Tad_pE!6f#BI z90Gu&BzgewgSm?vk}2)zG<3jC(gQN?nQ1S4)(|BabvaC0&lrME?U0-GHt$SzPSg(g z9=j985VwN^Ojew)W_M`&V7xG(SJwB|IW8!J%UV1wbfbJhFbzgY%r^5LFj(A6Lkr`p z2!TxC)ULZGFzjE5yj3qXs13p9#ank+gHDRJX{MbIkSEW~8%TiTKMcqFUZ@k088{dB zMV_oRTLw+Z__C&2iIJhJk+0CSCK15~`*QA_yR9_e%$I9LyeZiW>>}-o+>e>`Xkg;= zwnq#=xV^ZAPVQp+l%kj#`Uu($djiyNVfG_vW&X1iwzSZowZ5e5v{1@+(<|7mKT0*s zTWHPZ-K4F}ib@uC9@1qys|@y-JiyKq2vEkPJ~8)jDD|Oe*c4RN+79E_a#jWR#FZVa zz%J${?AkFchuT?w#1>j{>IhB)gUu3k#GvXJVb6|ZU@CYnTAM~lEh%ZX^YtJp3YwWoPNw9$G_(^4~ZKAXXSgJV1T2^hw zs-b~e2<$M`^Mi%n%0Dx`Rgh(mYp!>71<)C-O9#Qmt00DZVOPkZ^1JXJJvD38w7X5Kwd zN-{DBK+;UpxT)vK;MYN`nc^Aw}taQj~@b!By;X1T!#tEnlAg{C{%)Lv#tusqcRnj4y`c;{6Yo-Te=z zfX8_MLwsG)DK3Ec7&fL}B^N+MuL~DIWN-W}y8%M@8h>&Hgh<->vtI!b@vY(ti0Cu# z?ttj-favakc!YOAL>ko}749CyaVd)}o#X5Mp}jDq(ZO&*>1eBZv* zV}!*2kA4Q=)c*f)G#(8K{(txTf2V=R=>Nw*SaAyfKRSS!^Z%pQ1^++$`x<5b|7MYM z|2Ih!$8i6BWcQ;<;yqdvLV!$!Q!`^c+@K;FjEbNl`rHK-pbILxpyCk*6_Exv2NhAt zHcohye|`%~@2fFimTOp1%XH}l@SyKYsgu?q^5Mg+3{r(xP$$JbXh%n;P}!7*IjMd?5I7i3akq?`A0w<}f z)Y^*|tT@+^jizNOwVtcOXZ0kgG_f}Id>4t*Ywh;C{7kl)z4weG>3pg=Uj2l$2@MkF zTL2Zm5Zm?Qv#`OMT^db$ShAK(q09Cz9#Gv@-5nREd%fgT2CHvWG^Slci)~M)d%6%= zV@8R|aZU3nWiOfy_D1PnGcv+v(6EO%KO{brZEVKK{O0Y6=7$ZDO^MSuW^J~>nQwkm zhjx(jqEXDE=B49kRT%yv2`1eyogsHdC#t8pG#rPUYZ*N^tKWUu6|+r=ji`)_Q(LoS z)LDZL)T_BcD~)5=IC?F*QpaXJG4Iir`m1qO`bW>+mES9F$OZ9ly;kT$!#Gv<3acPPbY!Lod1^%o^lD`RkU-nxC|gaRW1d@J3h-- z1Cq~$6@l=R$*Mq?Q124zT|zwrT|&KTG`oa)mr(B#>NVta33dIkOQ?4V^)8{_CDcoy sOQ?4V^%Ce3>M?W)^)8{_CDc3Upo0!NczE#d00030|4Y++>j1_809HX^O8@`> literal 0 HcmV?d00001 diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/Chart.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/Chart.yaml new file mode 100644 index 0000000..846adc5 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: hegel +description: An instance metadata service + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.3.3 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.11.1" diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/templates/deployment.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/templates/deployment.yaml new file mode 100644 index 0000000..2762846 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/templates/deployment.yaml @@ -0,0 +1,55 @@ +{{- if .Values.deploy }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.name }} + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ .Values.name }} + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 6 }} + {{- end }} + template: + metadata: + labels: + app: {{ .Values.name }} + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + - args: + - --backend=kubernetes + - --http-port={{ .Values.deployment.port }} + {{- range .Values.args }} + - {{ . }} + {{- end }} + env: + - name: HEGEL_TRUSTED_PROXIES + value: {{ required "missing trustedProxies" ( join "," .Values.trustedProxies | quote ) }} + {{- range $i, $env := .Values.env }} + - name: {{ $env.name | quote }} + value: {{ $env.value | quote }} + {{- end }} + image: {{ .Values.image }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + name: {{ .Values.name }} + ports: + - containerPort: {{ .Values.deployment.port }} + name: {{ .Values.deployment.portName }} + resources: + limits: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + requests: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + serviceAccountName: {{ .Values.name }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/templates/role.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/templates/role.yaml new file mode 100644 index 0000000..7682d10 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/templates/role.yaml @@ -0,0 +1,26 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Values.roleName }} + namespace: {{ .Release.Namespace | quote }} +rules: + - apiGroups: + - tinkerbell.org + resources: + - hardware + - hardware/status + verbs: + - get + - list + - watch + - apiGroups: + - tinkerbell.org + resources: + - workflows + - workflows/status + verbs: + - get + - list + - watch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/templates/rolebinding.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/templates/rolebinding.yaml new file mode 100644 index 0000000..523b9e9 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Values.roleBindingName }} + namespace: {{ .Release.Namespace | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Values.roleName }} +subjects: + - kind: ServiceAccount + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/templates/service-account.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/templates/service-account.yaml new file mode 100644 index 0000000..252282f --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/templates/service-account.yaml @@ -0,0 +1,7 @@ +{{- if .Values.deploy }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/templates/service.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/templates/service.yaml new file mode 100644 index 0000000..3552893 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/templates/service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.deploy -}} +apiVersion: v1 +kind: Service +metadata: + labels: + app: {{ .Values.name }} + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + ports: + - port: {{ .Values.service.port }} + protocol: TCP + targetPort: {{ .Values.deployment.portName }} + selector: + app: {{ .Values.name }} +{{- end -}} diff --git a/chart/tinkerbell-stack/dependency_charts/hegel/values.yaml b/chart/tinkerbell-stack/dependency_charts/hegel/values.yaml new file mode 100644 index 0000000..9759c4d --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/hegel/values.yaml @@ -0,0 +1,23 @@ +deploy: true +name: hegel +image: quay.io/tinkerbell/hegel:v0.11.1 +imagePullPolicy: IfNotPresent +replicas: 1 +service: + port: 50061 +deployment: + port: 50061 + portName: hegel-http +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi +roleName: hegel-role +roleBindingName: hegel-rolebinding + +# Trusted proxies defines a list of IP or CIDR ranges that are allowed to set the X-Forwarded-For +# header. This typically requires all Pod CIDRs in the cluster. +trustedProxies: [] diff --git a/chart/seeder/charts/rufio/Chart.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/Chart.yaml similarity index 96% rename from chart/seeder/charts/rufio/Chart.yaml rename to chart/tinkerbell-stack/dependency_charts/rufio/Chart.yaml index 7344b1f..c1ba7a2 100644 --- a/chart/seeder/charts/rufio/Chart.yaml +++ b/chart/tinkerbell-stack/dependency_charts/rufio/Chart.yaml @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.2.6 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: "0.3.2" diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_jobs.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_jobs.yaml new file mode 100644 index 0000000..3ad0b75 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_jobs.yaml @@ -0,0 +1,187 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: jobs.bmc.tinkerbell.org +spec: + group: bmc.tinkerbell.org + names: + categories: + - tinkerbell + kind: Job + listKind: JobList + plural: jobs + shortNames: + - j + singular: job + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Job is the Schema for the bmcjobs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: JobSpec defines the desired state of Job + properties: + machineRef: + description: MachineRef represents the Machine resource to execute + the job. All the tasks in the job are executed for the same Machine. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + tasks: + description: Tasks represents a list of baseboard management actions + to be executed. The tasks are executed sequentially. Controller + waits for one task to complete before executing the next. If a single + task fails, job execution stops and sets condition Failed. Condition + Completed is set only if all the tasks were successful. + items: + description: Action represents the action to be performed. A single + task can only perform one type of action. For example either PowerAction + or OneTimeBootDeviceAction. + maxProperties: 1 + properties: + oneTimeBootDeviceAction: + description: OneTimeBootDeviceAction represents a baseboard + management one time set boot device operation. + properties: + device: + description: Devices represents the boot devices, in order + for setting one time boot. Currently only the first device + in the slice is used to set one time boot. + items: + description: BootDevice represents boot device of the + Machine. + type: string + type: array + efiBoot: + description: EFIBoot instructs the machine to use EFI boot. + type: boolean + required: + - device + type: object + powerAction: + description: PowerAction represents a baseboard management power + operation. + enum: + - "on" + - "off" + - soft + - status + - cycle + - reset + type: string + virtualMediaAction: + description: VirtualMediaAction represents a baseboard management + virtual media insert/eject. + properties: + kind: + type: string + mediaURL: + description: mediaURL represents the URL of the image to + be inserted into the virtual media, or empty to eject + media. + type: string + required: + - kind + type: object + type: object + minItems: 1 + type: array + required: + - machineRef + - tasks + type: object + status: + description: JobStatus defines the observed state of Job + properties: + completionTime: + description: CompletionTime represents time when the job was completed. + The completion time is only set when the job finishes successfully. + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of an object's current state. + items: + properties: + message: + description: Message represents human readable message indicating + details about last transition. + type: string + status: + description: Status is the status of the Job condition. Can + be True or False. + type: string + type: + description: Type of the Job condition. + type: string + required: + - status + - type + type: object + type: array + startTime: + description: StartTime represents time when the Job controller started + processing a job. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_machines.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_machines.yaml new file mode 100644 index 0000000..73ecfd7 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_machines.yaml @@ -0,0 +1,124 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: machines.bmc.tinkerbell.org +spec: + group: bmc.tinkerbell.org + names: + categories: + - tinkerbell + kind: Machine + listKind: MachineList + plural: machines + singular: machine + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Machine is the Schema for the machines API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: MachineSpec defines desired machine state + properties: + connection: + description: Connection contains connection data for a Baseboard Management + Controller. + properties: + authSecretRef: + description: AuthSecretRef is the SecretReference that contains + authentication information of the Machine. The Secret must contain + username and password keys. + properties: + name: + description: Name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: Namespace defines the space within which the + secret name must be unique. + type: string + type: object + host: + description: Host is the host IP address or hostname of the Machine. + minLength: 1 + type: string + insecureTLS: + description: InsecureTLS specifies trusted TLS connections. + type: boolean + port: + default: 623 + description: Port is the port number for connecting with the Machine. + type: integer + required: + - authSecretRef + - host + - insecureTLS + - port + type: object + required: + - connection + type: object + status: + description: MachineStatus defines the observed state of Machine + properties: + conditions: + description: Conditions represents the latest available observations + of an object's current state. + items: + description: MachineCondition defines an observed condition of a + Machine. + properties: + lastUpdateTime: + description: LastUpdateTime of the condition. + format: date-time + type: string + message: + description: Message is a human readable message indicating + with details of the last transition. + type: string + status: + description: Status of the condition. + type: string + type: + description: Type of the Machine condition. + type: string + required: + - status + - type + type: object + type: array + powerState: + description: Power is the current power state of the Machine. + enum: + - "on" + - "off" + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_tasks.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_tasks.yaml new file mode 100644 index 0000000..be83d83 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/crds/bmc.tinkerbell.org_tasks.yaml @@ -0,0 +1,170 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: tasks.bmc.tinkerbell.org +spec: + group: bmc.tinkerbell.org + names: + categories: + - tinkerbell + kind: Task + listKind: TaskList + plural: tasks + shortNames: + - t + singular: task + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Task is the Schema for the Task API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TaskSpec defines the desired state of Task. + properties: + connection: + description: Connection represents the Machine connectivity information. + properties: + authSecretRef: + description: AuthSecretRef is the SecretReference that contains + authentication information of the Machine. The Secret must contain + username and password keys. + properties: + name: + description: Name is unique within a namespace to reference + a secret resource. + type: string + namespace: + description: Namespace defines the space within which the + secret name must be unique. + type: string + type: object + host: + description: Host is the host IP address or hostname of the Machine. + minLength: 1 + type: string + insecureTLS: + description: InsecureTLS specifies trusted TLS connections. + type: boolean + port: + default: 623 + description: Port is the port number for connecting with the Machine. + type: integer + required: + - authSecretRef + - host + - insecureTLS + - port + type: object + task: + description: Task defines the specific action to be performed. + maxProperties: 1 + properties: + oneTimeBootDeviceAction: + description: OneTimeBootDeviceAction represents a baseboard management + one time set boot device operation. + properties: + device: + description: Devices represents the boot devices, in order + for setting one time boot. Currently only the first device + in the slice is used to set one time boot. + items: + description: BootDevice represents boot device of the Machine. + type: string + type: array + efiBoot: + description: EFIBoot instructs the machine to use EFI boot. + type: boolean + required: + - device + type: object + powerAction: + description: PowerAction represents a baseboard management power + operation. + enum: + - "on" + - "off" + - soft + - status + - cycle + - reset + type: string + virtualMediaAction: + description: VirtualMediaAction represents a baseboard management + virtual media insert/eject. + properties: + kind: + type: string + mediaURL: + description: mediaURL represents the URL of the image to be + inserted into the virtual media, or empty to eject media. + type: string + required: + - kind + type: object + type: object + required: + - task + type: object + status: + description: TaskStatus defines the observed state of Task + properties: + completionTime: + description: CompletionTime represents time when the task was completed. + The completion time is only set when the task finishes successfully. + format: date-time + type: string + conditions: + description: Conditions represents the latest available observations + of an object's current state. + items: + properties: + message: + description: Message represents human readable message indicating + details about last transition. + type: string + status: + description: Status is the status of the Task condition. Can + be True or False. + type: string + type: + description: Type of the Task condition. + type: string + required: + - status + - type + type: object + type: array + startTime: + description: StartTime represents time when the Task started processing. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role-binding.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role-binding.yaml new file mode 100644 index 0000000..bdcd222 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role-binding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.managerRoleBindingName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.managerRoleName }} +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccountName }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/seeder/charts/rufio/templates/role.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role.yaml similarity index 75% rename from chart/seeder/charts/rufio/templates/role.yaml rename to chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role.yaml index c7422a2..3098634 100644 --- a/chart/seeder/charts/rufio/templates/role.yaml +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/cluster-role.yaml @@ -1,22 +1,22 @@ ---- +{{- if .Values.deploy }}--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: creationTimestamp: null - name: {{ include "rufio.fullname" . }}-manager-role + name: {{ .Values.managerRoleName }} rules: - apiGroups: - - "" + - "" resources: - - secrets + - secrets verbs: - - get - - list - - watch + - get + - list + - watch - apiGroups: - bmc.tinkerbell.org resources: - - baseboardmanagements + - jobs verbs: - create - delete @@ -28,13 +28,13 @@ rules: - apiGroups: - bmc.tinkerbell.org resources: - - baseboardmanagements/finalizers + - jobs/finalizers verbs: - update - apiGroups: - bmc.tinkerbell.org resources: - - baseboardmanagements/status + - jobs/status verbs: - get - patch @@ -42,7 +42,7 @@ rules: - apiGroups: - bmc.tinkerbell.org resources: - - bmcjobs + - machines verbs: - create - delete @@ -54,13 +54,13 @@ rules: - apiGroups: - bmc.tinkerbell.org resources: - - bmcjobs/finalizers + - machines/finalizers verbs: - update - apiGroups: - bmc.tinkerbell.org resources: - - bmcjobs/status + - machines/status verbs: - get - patch @@ -68,7 +68,7 @@ rules: - apiGroups: - bmc.tinkerbell.org resources: - - bmctasks + - tasks verbs: - create - delete @@ -80,14 +80,15 @@ rules: - apiGroups: - bmc.tinkerbell.org resources: - - bmctasks/finalizers + - tasks/finalizers verbs: - update - apiGroups: - bmc.tinkerbell.org resources: - - bmctasks/status + - tasks/status verbs: - get - patch - update +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/templates/deployment.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/deployment.yaml new file mode 100644 index 0000000..9580b24 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/deployment.yaml @@ -0,0 +1,59 @@ +{{- if .Values.deploy }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.name }} + control-plane: controller-manager + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + selector: + matchLabels: + app: {{ .Values.name }} + control-plane: controller-manager + stack: tinkerbell + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + app: {{ .Values.name }} + control-plane: controller-manager + stack: tinkerbell + spec: + securityContext: + runAsNonRoot: true + containers: + - name: manager + image: {{ .Values.image }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + command: + - /manager + args: + - --leader-elect + securityContext: + allowPrivilegeEscalation: false + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + requests: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + serviceAccountName: {{ .Values.serviceAccountName }} + terminationGracePeriodSeconds: 10 +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role-binding.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role-binding.yaml new file mode 100644 index 0000000..1d3588d --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role-binding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Values.rufioLeaderElectionRoleBindingName }} + namespace: {{ .Release.Namespace | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Values.rufioLeaderElectionRoleName }} +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccountName }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role.yaml new file mode 100644 index 0000000..ca1c5db --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/leader-election-role.yaml @@ -0,0 +1,39 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Values.rufioLeaderElectionRoleName }} + namespace: {{ .Release.Namespace | quote }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/templates/service-account.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/templates/service-account.yaml new file mode 100644 index 0000000..049742b --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/templates/service-account.yaml @@ -0,0 +1,7 @@ +{{- if .Values.deploy }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccountName }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/rufio/values.yaml b/chart/tinkerbell-stack/dependency_charts/rufio/values.yaml new file mode 100644 index 0000000..729d969 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/rufio/values.yaml @@ -0,0 +1,16 @@ +deploy: true +name: rufio +image: quay.io/tinkerbell/rufio:v0.3.2 +imagePullPolicy: IfNotPresent +resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 500m + memory: 128Mi +serviceAccountName: rufio-controller-manager +rufioLeaderElectionRoleName: rufio-leader-election-role +managerRoleName: rufio-manager-role +rufioLeaderElectionRoleBindingName: rufio-leader-election-rolebinding +managerRoleBindingName: rufio-manager-rolebinding diff --git a/chart/seeder/charts/boots/Chart.yaml b/chart/tinkerbell-stack/dependency_charts/smee/Chart.yaml similarity index 95% rename from chart/seeder/charts/boots/Chart.yaml rename to chart/tinkerbell-stack/dependency_charts/smee/Chart.yaml index 543fbf8..342e489 100644 --- a/chart/seeder/charts/boots/Chart.yaml +++ b/chart/tinkerbell-stack/dependency_charts/smee/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v2 -name: boots +name: smee description: A Helm chart for Kubernetes # A chart can be either an 'application' or a 'library' chart. @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +version: 0.3.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.0" +appVersion: "0.10.1" diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/_ports.tpl b/chart/tinkerbell-stack/dependency_charts/smee/templates/_ports.tpl new file mode 100644 index 0000000..48b4924 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/_ports.tpl @@ -0,0 +1,20 @@ +{{ define "smee.ports" }} +- {{ .PortKey }}: {{ .http.port }} + name: {{ .http.name }} + protocol: TCP +- {{ .PortKey }}: {{ .syslog.port }} + name: {{ .syslog.name }} + protocol: UDP +- {{ .PortKey }}: {{ .dhcp.port }} + name: {{ .dhcp.name }} + protocol: UDP +- {{ .PortKey }}: {{ .tftp.port }} + name: {{ .tftp.name }} + protocol: UDP +{{- end }} + +{{- define "urlJoiner" }} +{{- $host := printf "%v:%v" .urlDict.host .urlDict.port }} +{{- $newDict := set .urlDict "host" $host }} +{{- print (urlJoin $newDict) }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role-binding.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role-binding.yaml new file mode 100644 index 0000000..0445fb8 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role-binding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.roleBindingName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.roleName }} +subjects: + - kind: ServiceAccount + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role.yaml new file mode 100644 index 0000000..4e49516 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/cluster-role.yaml @@ -0,0 +1,25 @@ +{{- if .Values.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Values.roleName }} +rules: + - apiGroups: + - tinkerbell.org + resources: + - hardware + - hardware/status + verbs: + - get + - list + - watch + - apiGroups: + - tinkerbell.org + resources: + - workflows + - workflows/status + verbs: + - get + - list + - watch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/deployment.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/deployment.yaml new file mode 100644 index 0000000..d10e52b --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/deployment.yaml @@ -0,0 +1,92 @@ +{{- if .Values.deploy }} +{{- $_ := set .Values.dhcp "syslogIp" (default .Values.publicIP .Values.dhcp.syslogIp) }} +{{- $_ := set .Values.dhcp "ipForPacket" (default .Values.publicIP .Values.dhcp.ipForPacket) }} +{{- $_ := set .Values.dhcp "tftpIp" (default .Values.publicIP .Values.dhcp.tftpIp) }} +{{- $_ := set .Values.dhcp.httpIPXE.binaryUrl "host" (default .Values.publicIP .Values.dhcp.httpIPXE.binaryUrl.host) }} +{{- $_ := set .Values.dhcp.httpIPXE.scriptUrl "host" (default .Values.publicIP .Values.dhcp.httpIPXE.scriptUrl.host) }} +{{- $_ := set .Values.http.tinkServer "ip" (default .Values.publicIP .Values.http.tinkServer.ip) }} +{{- $_ := set .Values.http.osieUrl "host" (default .Values.publicIP .Values.http.osieUrl.host) }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.name }} + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ .Values.name }} + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 6 }} + {{- end }} + strategy: + type: {{ .Values.deployment.strategy.type }} + template: + metadata: + labels: + app: {{ .Values.name }} + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.hostNetwork }} + hostNetwork: true + {{- end }} + containers: + - image: {{ .Values.image }} + imagePullPolicy: {{ .Values.imagePullPolicy }} + args: + - -log-level={{ .Values.logLevel }} + - -backend-kube-namespace={{ .Release.Namespace }} + - -dhcp-addr={{ printf "%v:%v" .Values.dhcp.ip .Values.dhcp.port }} + - -dhcp-enabled={{ .Values.dhcp.enabled }} + - -dhcp-http-ipxe-binary-url={{include "urlJoiner" (dict "urlDict" .Values.dhcp.httpIPXE.binaryUrl)}} + - -dhcp-http-ipxe-script-url={{include "urlJoiner" (dict "urlDict" .Values.dhcp.httpIPXE.scriptUrl)}} + - -dhcp-ip-for-packet={{ .Values.dhcp.ipForPacket }} + - -dhcp-syslog-ip={{ .Values.dhcp.syslogIp }} + - -dhcp-tftp-ip={{ .Values.dhcp.tftpIp }}:69 + - -extra-kernel-args={{ join " " ( append .Values.http.additionlKernelArgs ( printf "tink_worker_image=%s" ( required "missing tinkWorkerImage" .Values.tinkWorkerImage ) ) ) }} + - -http-addr={{ printf "%v:%v" .Values.http.ip .Values.http.port }} + - -http-ipxe-binary-enabled={{ .Values.http.ipxeBinaryEnabled }} + - -http-ipxe-script-enabled={{ .Values.http.ipxeScriptEnabled }} + - -osie-url={{include "urlJoiner" (dict "urlDict" .Values.http.osieUrl)}} + - -tink-server={{ printf "$(PUBLIC_IP):%v" .Values.http.tinkServer.port }} + - -tink-server-tls={{ .Values.http.tinkServer.tls }} + - -trusted-proxies={{ required "missing trustedProxies" ( join "," .Values.trustedProxies ) }} + - -syslog-addr={{ printf "%v:%v" .Values.syslog.ip .Values.syslog.port }} + - -syslog-enabled={{ .Values.syslog.enabled }} + - -ipxe-script-patch={{ .Values.ipxeScriptPatch }} + - -tftp-addr={{ printf "%v:%v" .Values.tftp.ip .Values.tftp.port }} + - -tftp-enabled={{ .Values.tftp.enabled }} + - -tftp-timeout={{ .Values.tftp.timeout }} + {{- range .Values.additionalArgs }} + - {{ . }} + {{- end }} + env: + - name: PUBLIC_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + {{- range .Values.additionalEnv }} + - name: {{ .name | quote }} + value: {{ .value | quote }} + {{- end }} + {{- if not .Values.hostNetwork }} + ports: + {{- include "smee.ports" ( merge ( dict "PortKey" "containerPort" ) .Values ) | indent 12 }} + {{- end }} + name: {{ .Values.name }} + resources: + limits: + cpu: {{ .Values.resources.limits.cpu }} + memory: {{ .Values.resources.limits.memory }} + requests: + cpu: {{ .Values.resources.requests.cpu }} + memory: {{ .Values.resources.requests.memory }} + serviceAccountName: {{ .Values.name }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-configmap.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-configmap.yaml new file mode 100644 index 0000000..eab8947 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-configmap.yaml @@ -0,0 +1,52 @@ +# The NGINX ConfigMap is in a separate file because its checksum is used to trigger updates in +# the deployment. +{{ if .Values.deploy -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-conf + namespace: {{ .Release.Namespace | quote }} +data: + nginx.conf: | + worker_processes 1; + events { + worker_connections 1024; + } + user root; + + http { + server { + listen 50061; + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + resolver $POD_NAMESERVER; + set $hegel_dns hegel.{{ .Release.Namespace }}.svc.cluster.local.; # needed in Kubernetes for dynamic DNS resolution + + proxy_pass http://$hegel_dns:50061; + } + } + + server { + listen 42113; + http2 on; + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + resolver $POD_NAMESERVER; + set $tink_dns tink-server.{{ .Release.Namespace }}.svc.cluster.local.; # needed in Kubernetes for dynamic DNS resolution + + grpc_pass grpc://$tink_dns:42113; + } + } + + server { + listen 8080; + location / { + sendfile on; + sendfile_max_chunk 1m; + root /usr/share/nginx/html; + } + } + } +{{- end }} \ No newline at end of file diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-deploy.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-deploy.yaml new file mode 100644 index 0000000..b540693 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/nginx-deploy.yaml @@ -0,0 +1,87 @@ +{{- if .Values.deploy }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.name }}-nginx + name: {{ .Values.name }}-nginx + namespace: {{ .Release.Namespace | quote }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + app: {{ .Values.name }}-nginx + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 6 }} + {{- end }} + strategy: + type: {{ .Values.deployment.strategy.type }} + template: + metadata: + labels: + app: {{ .Values.name }}-nginx + stack: tinkerbell + {{- with .Values.selector }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - {{ .Values.name }} + containers: + - name: {{ .Values.name }}-nginx + image: {{ .Values.nginxImage }} + command: ["/bin/bash", "-xeuc"] + args: + - | + POD_NAMESERVER=$(awk '/nameserver/ {print $2}' /etc/resolv.conf) \ + envsubst '$POD_NAMESERVER' \ + /etc/nginx/nginx.conf + exec nginx -g 'daemon off;' + ports: + - containerPort: 50061 + hostPort: 50061 + protocol: TCP + name: hegel-port + - containerPort: 42113 + hostPort: 42113 + protocol: TCP + name: tink-server + - containerPort: 8080 + hostPort: 8080 + protocol: TCP + name: hook-http + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + volumeMounts: + - mountPath: /tmp + readOnly: true + name: nginx-conf + - mountPath: /usr/share/nginx/html + name: hook-artifacts + volumes: + - name: nginx-conf + configMap: + name: nginx-conf + items: + - key: nginx.conf + path: nginx.conf.template + - name: hook-artifacts + hostPath: + path: /opt/hook + type: DirectoryOrCreate + serviceAccountName: {{ .Values.name }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/service-account.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/service-account.yaml new file mode 100644 index 0000000..252282f --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/service-account.yaml @@ -0,0 +1,7 @@ +{{- if .Values.deploy }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/templates/service.yaml b/chart/tinkerbell-stack/dependency_charts/smee/templates/service.yaml new file mode 100644 index 0000000..c66f7b1 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/templates/service.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: {{ .Values.name }} + name: {{ .Values.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + type: ClusterIP + ports: + - name: tftp + port: 69 + targetPort: 69 + protocol: UDP + - name: http + port: {{ .Values.http.port }} + targetPort: {{ .Values.http.port }} + protocol: TCP + - name: syslog + port: {{ .Values.syslog.port }} + targetPort: {{ .Values.syslog.port }} + protocol: UDP + - name: dhcp + port: 67 + targetPort: 67 + protocol: UDP + selector: + app: {{ .Values.name }} diff --git a/chart/tinkerbell-stack/dependency_charts/smee/values.yaml b/chart/tinkerbell-stack/dependency_charts/smee/values.yaml new file mode 100644 index 0000000..d47ca60 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/smee/values.yaml @@ -0,0 +1,131 @@ +# Toggle deployment of the service. +deploy: true + +# Name of the service used as the deployment name and label selectors. +name: smee + +# The image used to launch the container. +image: quay.io/tinkerbell/smee:v0.10.1 +imagePullPolicy: IfNotPresent + +# The number of pods to run. +replicas: 1 + +# Resources bounds applied to the container. +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + +roleName: smee-role +roleBindingName: smee-rolebinding + +deployment: + strategy: + type: RollingUpdate + +# The log level for the container. +logLevel: "info" + +# The network mode to launch the smee container. When true, the smee container will use the +# host network. +hostNetwork: false + +# publicIP when defined will be used as the IP in the following locations if they are not defined: +# dhcp.httpIPXE.binaryUrl.host, dhcp.httpIPXE.scriptUrl.host, tinkServer.ip, http.osieUrl.host, dhcp.ipForPacket, dhcp.tftpIp +# This is useful when all Tinkerbell services are running behind the same IP. +publicIP: "127.0.0.1" + +# DHCP server configuration. Name is an identifier used across Kubernetes manifests for port +# identification, ip is the IP address to bind to, and port is the port to bind to. +dhcp: + enabled: true + name: smee-dhcp + ip: 0.0.0.0 + port: 67 + ipForPacket: "" + tftpIp: "" + syslogIp: "" + httpIPXE: + binaryUrl: # http://:/ipxe + scheme: "http" + host: "" + port: 7171 + path: "/ipxe" + scriptUrl: # http://:/auto.ipxe + scheme: "http" + host: "" + port: 7171 + path: "/auto.ipxe" + + +# TFTP server configuration used to serve iPXE binaries. Name is an identifier used across +# Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the +# port to bind to. +tftp: + enabled: true + name: smee-tftp + ip: 0.0.0.0 + port: 69 + timeout: 5s + +# HTTP server configuration used to serve iPXE scripts. Name is an identifier used across +# Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the +# port to bind to. +http: + enabled: true + name: smee-http + ip: 0.0.0.0 + port: 7171 + # Tink Server configuration passed to the Tink Worker to establish a gRPC connection. + tinkServer: + ip: "" + port: 42113 + tls: false + osieUrl: + scheme: "http" + host: "" + port: 8080 + path: "" + # Additional kernel arguments to pass to the OSIE. (k=v k=v) that are appended to the kernel cmdline in the iPXE script + additionlKernelArgs: [] + # enable iPXE HTTP binary server + ipxeBinaryEnabled: true + # enable iPXE HTTP script server + ipxeScriptEnabled: true + +# Trusted proxies defines a list of IP or CIDR ranges that are allowed to set the X-Forwarded-For + # header. This typically requires all Pod CIDRs in the cluster. + trustedProxies: [] + +# Syslog server configuration for the smee hosted syslog server. Name is an identifier used across +# Kubernetes manifests for port identification, ip is the IP address to bind to, and port is the +# port to bind to. +syslog: + enabled: true + name: smee-syslog + ip: 0.0.0.0 + port: 514 + +# The Tink Worker image passed to OSIE as a kernel arg for launching. +tinkWorkerImage: quay.io/tinkerbell/tink-worker:v0.9.0 + + +# Additional arguments to pass to the smee container. Some arguments are already defined - refer +# to the deployment.yaml template for details. +additionalArgs: [] + +# Additional environment variables to pass to the smee container. Each entry is expected to have a +# name and value key. Some keys are already defined - refer to the deployment.yaml template for +# details. +# +# Example +# - name: MY_ENV_VAR +# value: my-value +additionalEnv: [] +trustedProxies: + - "10.42.0.0/24" +nginxImage: nginx:1.25.1 \ No newline at end of file diff --git a/chart/tinkerbell-stack/dependency_charts/tink/Chart.yaml b/chart/tinkerbell-stack/dependency_charts/tink/Chart.yaml new file mode 100644 index 0000000..219ec76 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: tink +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.2.2 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.9.0" diff --git a/chart/tinkerbell-stack/dependency_charts/tink/crds/hardware-crd.yaml b/chart/tinkerbell-stack/dependency_charts/tink/crds/hardware-crd.yaml new file mode 100644 index 0000000..3cf890e --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/crds/hardware-crd.yaml @@ -0,0 +1,393 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: hardware.tinkerbell.org +spec: + group: tinkerbell.org + names: + categories: + - tinkerbell + kind: Hardware + listKind: HardwareList + plural: hardware + shortNames: + - hw + singular: hardware + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Hardware is the Schema for the Hardware API. + properties: + apiVersion: + description: + "APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" + type: string + kind: + description: + "Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + type: string + metadata: + type: object + spec: + description: HardwareSpec defines the desired state of Hardware. + properties: + bmcRef: + description: + BMCRef contains a relation to a BMC state management + type in the same namespace as the Hardware. This may be used for + BMC management by orchestrators. + properties: + apiGroup: + description: + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + disks: + items: + description: Disk represents a disk device for Tinkerbell Hardware. + properties: + device: + type: string + type: object + type: array + interfaces: + items: + description: + Interface represents a network interface configuration + for Hardware. + properties: + dhcp: + description: DHCP configuration. + properties: + arch: + type: string + hostname: + type: string + iface_name: + type: string + ip: + description: IP configuration. + properties: + address: + type: string + family: + format: int64 + type: integer + gateway: + type: string + netmask: + type: string + type: object + lease_time: + format: int64 + type: integer + mac: + pattern: ([0-9a-f]{2}[:]){5}([0-9a-f]{2}) + type: string + name_servers: + items: + type: string + type: array + time_servers: + items: + type: string + type: array + uefi: + type: boolean + vlan_id: + description: + validation pattern for VLANDID is a string + number between 0-4096 + pattern: ^(([0-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))(,[1-9][0-9]{0,2}|[1-3][0-9][0-9][0-9]|40([0-8][0-9]|9[0-6]))*)$ + type: string + type: object + netboot: + description: Netboot configuration. + properties: + allowPXE: + type: boolean + allowWorkflow: + type: boolean + ipxe: + description: IPXE configuration. + properties: + contents: + type: string + url: + type: string + type: object + osie: + description: OSIE configuration. + properties: + baseURL: + type: string + initrd: + type: string + kernel: + type: string + type: object + type: object + type: object + type: array + metadata: + properties: + bonding_mode: + format: int64 + type: integer + custom: + properties: + preinstalled_operating_system_version: + properties: + distro: + type: string + image_tag: + type: string + os_slug: + type: string + slug: + type: string + version: + type: string + type: object + private_subnets: + items: + type: string + type: array + type: object + facility: + properties: + facility_code: + type: string + plan_slug: + type: string + plan_version_slug: + type: string + type: object + instance: + properties: + allow_pxe: + type: boolean + always_pxe: + type: boolean + crypted_root_password: + type: string + hostname: + type: string + id: + type: string + ips: + items: + properties: + address: + type: string + family: + format: int64 + type: integer + gateway: + type: string + management: + type: boolean + netmask: + type: string + public: + type: boolean + type: object + type: array + ipxe_script_url: + type: string + network_ready: + type: boolean + operating_system: + properties: + distro: + type: string + image_tag: + type: string + os_slug: + type: string + slug: + type: string + version: + type: string + type: object + rescue: + type: boolean + ssh_keys: + items: + type: string + type: array + state: + type: string + storage: + properties: + disks: + items: + properties: + device: + type: string + partitions: + items: + properties: + label: + type: string + number: + format: int64 + type: integer + size: + format: int64 + type: integer + start: + format: int64 + type: integer + type_guid: + type: string + type: object + type: array + wipe_table: + type: boolean + type: object + type: array + filesystems: + items: + properties: + mount: + properties: + create: + properties: + force: + type: boolean + options: + items: + type: string + type: array + type: object + device: + type: string + files: + items: + properties: + contents: + type: string + gid: + format: int64 + type: integer + mode: + format: int64 + type: integer + path: + type: string + uid: + format: int64 + type: integer + type: object + type: array + format: + type: string + point: + type: string + type: object + type: object + type: array + raid: + items: + properties: + devices: + items: + type: string + type: array + level: + type: string + name: + type: string + spare: + format: int64 + type: integer + type: object + type: array + type: object + tags: + items: + type: string + type: array + userdata: + type: string + type: object + manufacturer: + properties: + id: + type: string + slug: + type: string + type: object + state: + type: string + type: object + resources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: + Resources represents known resources that are available + on a machine. Resources may be used for scheduling by orchestrators. + type: object + tinkVersion: + format: int64 + type: integer + userData: + description: + UserData is the user data to configure in the hardware's + metadata + type: string + vendorData: + description: + VendorData is the vendor data to configure in the hardware's + metadata + type: string + type: object + status: + description: HardwareStatus defines the observed state of Hardware. + properties: + state: + description: HardwareState represents the hardware state. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/tink/crds/template-crd.yaml b/chart/tinkerbell-stack/dependency_charts/tink/crds/template-crd.yaml new file mode 100644 index 0000000..179124f --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/crds/template-crd.yaml @@ -0,0 +1,68 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: templates.tinkerbell.org +spec: + group: tinkerbell.org + names: + categories: + - tinkerbell + kind: Template + listKind: TemplateList + plural: templates + shortNames: + - tpl + singular: template + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Template is the Schema for the Templates API. + properties: + apiVersion: + description: + "APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" + type: string + kind: + description: + "Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + type: string + metadata: + type: object + spec: + description: TemplateSpec defines the desired state of Template. + properties: + data: + type: string + type: object + status: + description: TemplateStatus defines the observed state of Template. + properties: + state: + description: TemplateState represents the template state. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-crd.yaml b/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-crd.yaml new file mode 100644 index 0000000..7f09f3c --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-crd.yaml @@ -0,0 +1,146 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: workflows.tinkerbell.org +spec: + group: tinkerbell.org + names: + categories: + - tinkerbell + kind: Workflow + listKind: WorkflowList + plural: workflows + shortNames: + - wf + singular: workflow + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.templateRef + name: Template + type: string + - jsonPath: .status.state + name: State + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Workflow is the Schema for the Workflows API. + properties: + apiVersion: + description: + "APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" + type: string + kind: + description: + "Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + type: string + metadata: + type: object + spec: + description: WorkflowSpec defines the desired state of Workflow. + properties: + hardwareMap: + additionalProperties: + type: string + description: A mapping of template devices to hadware mac addresses + type: object + hardwareRef: + description: Name of the Hardware associated with this workflow. + type: string + templateRef: + description: Name of the Template associated with this workflow. + type: string + type: object + status: + description: WorkflowStatus defines the observed state of Workflow. + properties: + globalTimeout: + description: GlobalTimeout represents the max execution time + format: int64 + type: integer + state: + description: State is the state of the workflow in Tinkerbell. + type: string + tasks: + description: Tasks are the tasks to be completed + items: + description: + Task represents a series of actions to be completed + by a worker. + properties: + actions: + items: + description: Action represents a workflow action. + properties: + command: + items: + type: string + type: array + environment: + additionalProperties: + type: string + type: object + image: + type: string + message: + type: string + name: + type: string + pid: + type: string + seconds: + format: int64 + type: integer + startedAt: + format: date-time + type: string + status: + type: string + timeout: + format: int64 + type: integer + volumes: + items: + type: string + type: array + type: object + type: array + environment: + additionalProperties: + type: string + type: object + name: + type: string + volumes: + items: + type: string + type: array + worker: + type: string + required: + - actions + - name + - worker + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-data-crd.yaml b/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-data-crd.yaml new file mode 100644 index 0000000..cc9878f --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/crds/workflow-data-crd.yaml @@ -0,0 +1,139 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: workflowdata.tinkerbell.org +spec: + group: tinkerbell.org + names: + categories: + - tinkerbell + kind: WorkflowData + listKind: WorkflowDataList + plural: workflowdata + shortNames: + - wfdata + singular: workflowdata + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Workflow is the Schema for the Workflows API. + properties: + apiVersion: + description: + "APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources" + type: string + kind: + description: + "Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds" + type: string + metadata: + type: object + spec: + description: WorkflowSpec defines the desired state of Workflow. + properties: + hardwareMap: + additionalProperties: + type: string + description: A mapping of template devices to hadware mac addresses + type: object + hardwareRef: + description: Name of the Hardware associated with this workflow. + type: string + templateRef: + description: Name of the Template associated with this workflow. + type: string + type: object + status: + description: WorkflowStatus defines the observed state of Workflow. + properties: + globalTimeout: + description: GlobalTimeout represents the max execution time + format: int64 + type: integer + state: + description: State is the state of the workflow in Tinkerbell. + type: string + tasks: + description: Tasks are the tasks to be completed + items: + description: + Task represents a series of actions to be completed + by a worker. + properties: + actions: + items: + description: Action represents a workflow action. + properties: + command: + items: + type: string + type: array + environment: + additionalProperties: + type: string + type: object + image: + type: string + message: + type: string + name: + type: string + pid: + type: string + seconds: + format: int64 + type: integer + startedAt: + format: date-time + type: string + status: + type: string + timeout: + format: int64 + type: integer + volumes: + items: + type: string + type: array + type: object + type: array + environment: + additionalProperties: + type: string + type: object + name: + type: string + volumes: + items: + type: string + type: array + worker: + type: string + required: + - actions + - name + - worker + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role-binding.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role-binding.yaml new file mode 100644 index 0000000..ab5d106 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role-binding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.controller.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.controller.roleBindingName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.controller.roleName }} +subjects: + - kind: ServiceAccount + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role.yaml new file mode 100644 index 0000000..7570615 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/cluster-role.yaml @@ -0,0 +1,41 @@ +{{- if .Values.controller.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Values.controller.roleName }} +rules: + - apiGroups: + - tinkerbell.org + resources: + - hardware + - hardware/status + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: + - tinkerbell.org + resources: + - templates + - templates/status + verbs: + - get + - list + - patch + - update + - watch + - apiGroups: + - tinkerbell.org + resources: + - workflows + - workflows/status + verbs: + - delete + - get + - list + - patch + - update + - watch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/deployment.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/deployment.yaml new file mode 100644 index 0000000..b6ce6ac --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/deployment.yaml @@ -0,0 +1,37 @@ +{{- if .Values.controller.deploy }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.controller.name }} + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + replicas: {{ .Values.controller.replicas }} + selector: + matchLabels: + app: {{ .Values.controller.name }} + template: + metadata: + labels: + app: {{ .Values.controller.name }} + spec: + containers: + - image: {{ .Values.controller.image }} + imagePullPolicy: {{ .Values.controller.imagePullPolicy }} + {{- if .Values.controller.args }} + args: + {{- range .Values.controller.args }} + - {{ . }} + {{- end }} + {{- end }} + name: {{ .Values.controller.name }} + resources: + limits: + cpu: {{ .Values.controller.resources.limits.cpu }} + memory: {{ .Values.controller.resources.limits.memory }} + requests: + cpu: {{ .Values.controller.resources.requests.cpu }} + memory: {{ .Values.controller.resources.requests.memory }} + serviceAccountName: {{ .Values.controller.name }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-role.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-role.yaml new file mode 100644 index 0000000..51a285a --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-role.yaml @@ -0,0 +1,38 @@ +{{- if .Values.controller.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ .Values.controller.tinkLeaderElectionRoleName }} + namespace: {{ .Release.Namespace | quote }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-rolebinding.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-rolebinding.yaml new file mode 100644 index 0000000..2431924 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/leader-election-rolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.controller.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ .Values.controller.tinkLeaderElectionRoleBindingName }} + namespace: {{ .Release.Namespace | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ .Values.controller.tinkLeaderElectionRoleName }} +subjects: + - kind: ServiceAccount + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/service-account.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/service-account.yaml new file mode 100644 index 0000000..d2bc943 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-controller/service-account.yaml @@ -0,0 +1,7 @@ +{{- if .Values.controller.deploy }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role-binding.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role-binding.yaml new file mode 100644 index 0000000..b8d1c17 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role-binding.yaml @@ -0,0 +1,14 @@ +{{- if .Values.server.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Values.server.roleBindingName }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.server.roleName }} +subjects: + - kind: ServiceAccount + name: {{ .Values.server.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role.yaml new file mode 100644 index 0000000..ddb4d26 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/cluster-role.yaml @@ -0,0 +1,36 @@ +{{- if .Values.server.deploy }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Values.server.roleName }} +rules: + - apiGroups: + - tinkerbell.org + resources: + - hardware + - hardware/status + verbs: + - get + - list + - watch + - apiGroups: + - tinkerbell.org + resources: + - templates + - templates/status + verbs: + - get + - list + - watch + - apiGroups: + - tinkerbell.org + resources: + - workflows + - workflows/status + verbs: + - get + - list + - patch + - update + - watch +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/deployment.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/deployment.yaml new file mode 100644 index 0000000..5a3bd03 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/deployment.yaml @@ -0,0 +1,47 @@ +{{- if .Values.server.deploy }} +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: {{ .Values.server.name }} + name: {{ .Values.server.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + replicas: {{ .Values.server.replicas }} + selector: + matchLabels: + app: {{ .Values.server.name }} + stack: tinkerbell + {{- with .Values.server.selector }} + {{- toYaml . | nindent 6 }} + {{- end }} + template: + metadata: + labels: + app: {{ .Values.server.name }} + stack: tinkerbell + {{- with .Values.server.selector }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + containers: + - args: + - --backend=kubernetes + {{- range .Values.server.args }} + - {{ . }} + {{- end }} + image: {{ .Values.server.image }} + imagePullPolicy: {{ .Values.server.imagePullPolicy }} + name: server + ports: + - containerPort: {{ .Values.server.deployment.port }} + name: {{ .Values.server.deployment.portName }} + resources: + limits: + cpu: {{ .Values.server.resources.limits.cpu }} + memory: {{ .Values.server.resources.limits.memory }} + requests: + cpu: {{ .Values.server.resources.requests.cpu }} + memory: {{ .Values.server.resources.requests.memory }} + serviceAccountName: {{ .Values.server.name }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service-account.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service-account.yaml new file mode 100644 index 0000000..5046035 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service-account.yaml @@ -0,0 +1,7 @@ +{{- if .Values.server.deploy }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.server.name }} + namespace: {{ .Release.Namespace | quote }} +{{- end }} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service.yaml b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service.yaml new file mode 100644 index 0000000..786193e --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/templates/tink-server/service.yaml @@ -0,0 +1,16 @@ +{{- if .Values.server.deploy -}} +apiVersion: v1 +kind: Service +metadata: + labels: + app: {{ .Values.server.name }} + name: {{ .Values.server.name }} + namespace: {{ .Release.Namespace | quote }} +spec: + ports: + - port: {{ .Values.server.service.port }} + protocol: TCP + targetPort: {{ .Values.server.deployment.portName }} + selector: + app: {{ .Values.server.name }} +{{- end -}} diff --git a/chart/tinkerbell-stack/dependency_charts/tink/values.yaml b/chart/tinkerbell-stack/dependency_charts/tink/values.yaml new file mode 100644 index 0000000..b998509 --- /dev/null +++ b/chart/tinkerbell-stack/dependency_charts/tink/values.yaml @@ -0,0 +1,39 @@ +controller: + deploy: true + name: tink-controller + image: quay.io/tinkerbell/tink-controller:v0.9.0 + imagePullPolicy: IfNotPresent + replicas: 1 + args: [] + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + roleName: tink-controller-manager-role + roleBindingName: tink-controller-manager-rolebinding + tinkLeaderElectionRoleName: tink-leader-election-role + tinkLeaderElectionRoleBindingName: tink-leader-election-rolebinding + +server: + deploy: true + name: tink-server + image: quay.io/tinkerbell/tink:v0.9.0 + imagePullPolicy: IfNotPresent + replicas: 1 + service: + port: 42113 + deployment: + port: 42113 + portName: tink-grpc + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + roleName: tink-server-role + roleBindingName: tink-server-rolebinding diff --git a/chart/tinkerbell-stack/docs/arch.md b/chart/tinkerbell-stack/docs/arch.md new file mode 100644 index 0000000..3d0da72 --- /dev/null +++ b/chart/tinkerbell-stack/docs/arch.md @@ -0,0 +1,64 @@ +# Stack Architecture + +The following is a high level diagram of the stack architecture. The stack acts as a lightweight ingress. We don't use an existing ingress controller so as to allow users to bring their own and most/all ingresses don't do all the protocols we require (HTTP, TCP, UDP). With this setup all Tinkerbell services (tink server, hegel and smee) can be accessed via a single IP. + +```shell + ┌───────────┐ + ┌─────────────────┤ service ├──────────────────┐ + │ └───────────┘ │ + │ Port Protocol Backend Flow │ + │ ---- -------- ------------ │ + │ 50061 TCP Nginx -> Hegel │ + │ 42113 TCP Nginx -> Tink Server │ + │ 8080 TCP Nginx │ + │ 7171 TCP Nginx -> Smee │ + │ 69 UDP Nginx -> Smee │ + │ 514 UDP Nginx -> Smee │ + │ 67 UDP DHCP Relay -> Smee │ + └────────────────────────────────────────────────┘ + ┌───────────┐ +┌──────────────────────────────┤ pod ├───────────────────────────────┐ +│ └───────────┘ │ +│ ┌────────────────────────────────────┐ │ +│ │ init containers │ │ +│ │ │ │ +│ │ ┌──────────────┐ │ │ +│ │ │ │ │ │ +│ │ │ broadcast │ │ │ +│ │ │listener setup│ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ └──────────────┘ │ │ +│ │ │ │ +│ └────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────┐ │ +│ │ containers │ │ +│ │ │ │ +│ │ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ nginx │ │ dhcp relay │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ └──────────────┘ └──────────────┘ │ │ +│ │ │ │ │ │ +│ └─────────┼─────────────────┼────────┘ │ +│ │ │ │ +│ │ │ │ +└────────────────────────────┼─────────────────┼───────────────────────────┘ + ┌─────────────┼───────────┐ └────┐ + │ │ │ │ + │ │ 7171/TCP │ + 50061/TCP 42113/TCP 69/UDP 67/UDP + │ │ 514/UDP │ + │ │ │ │ + ▼ ▼ ▼ │ + ┌─────────┐ ┌─────────┐ ┌─────────┐ │ + │ │ │ │ │ │ │ + │ │ │ Tink │ │ │ │ + │ Hegel │ │ Server │ │ Smee │◀─┘ + │ │ │ │ │ │ + │ │ │ │ │ │ + └─────────┘ └─────────┘ └─────────┘ +``` \ No newline at end of file diff --git a/chart/tinkerbell-stack/kubectl.go-template b/chart/tinkerbell-stack/kubectl.go-template new file mode 100644 index 0000000..950319b --- /dev/null +++ b/chart/tinkerbell-stack/kubectl.go-template @@ -0,0 +1,5 @@ +{{- $first := true -}} +{{- range .items -}} +{{- if not $first}},{{else}}{{$first = false}}{{end -}} +{{- .spec.podCIDR -}} +{{- end -}} \ No newline at end of file diff --git a/chart/tinkerbell-stack/templates/hook.yaml b/chart/tinkerbell-stack/templates/hook.yaml new file mode 100644 index 0000000..90f12df --- /dev/null +++ b/chart/tinkerbell-stack/templates/hook.yaml @@ -0,0 +1,56 @@ +{{- if .Values.stack.hook.enabled }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: download-hook + namespace: {{ .Release.Namespace }} +data: + entrypoint.sh: |- + #!/usr/bin/env bash + # This script is designed to download the Hook artifacts. + set -euxo pipefail + cd /output + rm -f *.tar.gz checksum.txt vmlinuz* initramfs* + base_loc="{{ .Values.stack.hook.downloadURL }}" + files="$base_loc/hook_aarch64.tar.gz $base_loc/hook_x86_64.tar.gz" + tmp_dir=$(mktemp -d) + for f in ${files}; do + echo "${f}" + wget -P "${tmp_dir}" "${f}" + done + for f in ${tmp_dir}/*.tar.gz; do tar --no-same-permissions --overwrite -ozxvf "${f}" && rm -f "${f}"; done + rm -rf "${tmp_dir}" +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: download-hook + namespace: {{ .Release.Namespace }} +spec: + backoffLimit: 50 + template: + metadata: + labels: + app: download-hook + spec: + containers: + - name: download-hook + image: {{ .Values.stack.hook.image }} + command: ["/script/entrypoint.sh"] + volumeMounts: + - mountPath: /output + name: hook-artifacts + - mountPath: /script + name: configmap-volume + restartPolicy: OnFailure + volumes: + - name: hook-artifacts + hostPath: + path: {{ .Values.stack.hook.downloadsDest }} + type: DirectoryOrCreate + - name: configmap-volume + configMap: + defaultMode: 0700 + name: download-hook +{{- end }} \ No newline at end of file diff --git a/chart/tinkerbell-stack/values.yaml b/chart/tinkerbell-stack/values.yaml new file mode 100644 index 0000000..103ee3b --- /dev/null +++ b/chart/tinkerbell-stack/values.yaml @@ -0,0 +1,39 @@ +stack: + hook: + enabled: true + name: hook-files + port: 8080 + image: bash + downloadsDest: /opt/hook + # downloadURL only works with the > 0.8.1 Hook release because + # previous Hook versions didn't provide a checksum file. + downloadURL: https://github.com/tinkerbell/hook/releases/download/v0.8.1 +# -- Overrides +# The values defined here override those in the individual charts. Some of them require tweaking +# before deployment as they are environment dependent; others are surfaced for convenience. +# +# See individual chart documentation for additional detail. +podCIDR: &range ["10.42.0.0/24"] +publicIP: &publicIP "$(PUBLIC_IP)" +smee: + image: quay.io/tinkerbell/smee:v0.10.1 + tinkWorkerImage: quay.io/tinkerbell/tink-worker:v0.9.0 + trustedProxies: *range + publicIP: *publicIP + hostNetwork: true + deployment: + strategy: + type: Recreate + +hegel: + image: quay.io/tinkerbell/hegel:v0.11.1 + trustedProxies: *range + +rufio: + image: quay.io/tinkerbell/rufio:v0.3.2 + +tink: + controller: + image: quay.io/tinkerbell/tink-controller:v0.9.0 + server: + image: quay.io/tinkerbell/tink:v0.9.0 diff --git a/go.mod b/go.mod index ad9e7fa..b471c75 100644 --- a/go.mod +++ b/go.mod @@ -6,23 +6,23 @@ require ( github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/go-logr/logr v1.2.4 github.com/google/uuid v1.3.0 + github.com/gorilla/mux v1.8.0 github.com/harvester/webhook v0.1.4 github.com/onsi/ginkgo/v2 v2.11.0 github.com/onsi/gomega v1.27.10 - github.com/pkg/errors v0.9.1 github.com/rancher/dynamiclistener v0.3.5 github.com/rancher/wrangler v1.1.1 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.2 github.com/stmcginnis/gofish v0.14.1-0.20230920133920-77490fd98fa2 - github.com/stretchr/testify v1.8.2 - github.com/tinkerbell/rufio v0.3.0 - github.com/tinkerbell/tink v0.6.0 + github.com/stretchr/testify v1.8.4 + github.com/tinkerbell/rufio v0.3.2 + github.com/tinkerbell/tink v0.9.0 github.com/urfave/cli/v2 v2.25.3 golang.org/x/net v0.17.0 golang.org/x/sync v0.4.0 - inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 - k8s.io/api v0.28.2 - k8s.io/apimachinery v0.28.2 + inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a + k8s.io/api v0.28.3 + k8s.io/apimachinery v0.28.3 k8s.io/client-go v12.0.0+incompatible sigs.k8s.io/controller-runtime v0.16.2 @@ -30,119 +30,123 @@ require ( require ( dario.cat/mergo v1.0.0 // indirect - github.com/Jeffail/gabs/v2 v2.7.0 // indirect - github.com/bmc-toolbox/bmclib/v2 v2.1.1-0.20231017114451-153e11d62a71 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/jacobweinstock/iamt v0.0.0-20230502042727-d7cdbe67d9ef // indirect -) - -require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/Microsoft/go-winio v0.5.2 // indirect + github.com/Jeffail/gabs/v2 v2.7.0 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 // indirect github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 // indirect - github.com/beorn7/perks v1.0.1 // indirect + github.com/bmc-toolbox/bmclib/v2 v2.1.1-0.20231017114451-153e11d62a71 // indirect github.com/bmc-toolbox/common v0.0.0-20230220061748-93ff001f4a1d // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/containerd/continuity v0.3.0 // indirect + github.com/coreos/yaml v0.0.0-20141224210557-6b16a5714269 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v20.10.14+incompatible // indirect - github.com/docker/docker v20.10.14+incompatible // indirect + github.com/docker/cli v20.10.20+incompatible // indirect + github.com/docker/docker v24.0.2+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/docker/go-units v0.5.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/zapr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.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.3 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/gorilla/mux v1.8.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/itchyny/gojq v0.12.2 // indirect + github.com/itchyny/timefmt-go v0.1.2 // indirect + github.com/jacobweinstock/iamt v0.0.0-20230502042727-d7cdbe67d9ef // indirect github.com/jacobweinstock/registrar v0.4.7 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kisielk/errcheck v1.5.0 // indirect github.com/lib/pq v1.10.2 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mattn/go-shellwords v1.0.10 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mudler/yip v0.0.0-20211129144714-088f39125cf7 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/opencontainers/runc v1.1.2 // indirect - github.com/ory/dockertest/v3 v3.9.1 - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.10.1 // indirect - github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/rancher-sandbox/cloud-init v1.14.3-0.20210913085759-bf90bf5eb77e // indirect + github.com/rancher/mapper v0.0.0-20190814232720-058a8b7feb99 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/tredoe/osutil v1.3.6 // indirect + github.com/twpayne/go-vfs v1.5.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect - go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 // indirect + go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230127130021-4ca2cb1a16b7 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/oauth2 v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect + k8s.io/klog v1.0.0 // indirect + k8s.io/kube-aggregator v0.25.4 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/zapr v1.2.4 // 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.3 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/harvester/harvester-installer v1.3.0-rc4 + github.com/imdario/mergo v0.3.13 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/ory/dockertest/v3 v3.9.1 + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc // indirect + github.com/spf13/pflag v1.0.5 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.25.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.0 // indirect - k8s.io/component-base v0.28.2 // indirect - k8s.io/klog v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 + k8s.io/apiextensions-apiserver v0.28.3 // indirect + k8s.io/component-base v0.28.3 // indirect k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-aggregator v0.25.4 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.3.0 ) replace ( - github.com/tinkerbell/rufio => github.com/tinkerbell/rufio v0.3.2 - github.com/tinkerbell/tink v0.6.0 => github.com/tinkerbell/tink v0.6.1-0.20220524234633-0a800a4b5e25 - go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 => go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 - k8s.io/api => k8s.io/api v0.28.2 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.2 - k8s.io/apimachinery => k8s.io/apimachinery v0.28.2 + github.com/harvester/harvester-install => github.com/harvester/harvester-installer v1.3.0 + github.com/tredoe/osutil => github.com/tredoe/osutil v1.5.0 k8s.io/client-go => k8s.io/client-go v0.28.2 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.2 - sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.15.0 ) diff --git a/go.sum b/go.sum index 64fa3d6..f52847f 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,111 @@ +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +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.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= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +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.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= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 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/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= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= -github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= -github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 h1:t95Grn2mOPfb3+kPDWsNnj4dlNcxnvuR72IjY8eYjfQ= github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230/go.mod h1:t2EzW1qybnPDQ3LR/GgeF0GOzHUXT5IVMLP2gkW1cmc= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 h1:a0MBqYm44o0NcthLKCljZHe1mxlN6oahCQHHThnSwB4= github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22/go.mod h1:/B7V22rcz4860iDqstGvia/2+IYWXf3/JdQCVd/1D2A= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= +github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +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-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/bmatcuk/doublestar v1.3.0 h1:1jLE2y0VpSrOn/QR9G4f2RmrCtkM3AuATcWradjHUvM= +github.com/bmatcuk/doublestar v1.3.0/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/bmc-toolbox/bmclib/v2 v2.1.1-0.20231017114451-153e11d62a71 h1:Dd76cvKu9/bRl6MKFASf+UmqyqwTdApmvgCvdab078w= github.com/bmc-toolbox/bmclib/v2 v2.1.1-0.20231017114451-153e11d62a71/go.mod h1:hRe0RhyHbyQDFULc6HQFBIwdBOFYnm+8rHeO9UBnxAU= github.com/bmc-toolbox/common v0.0.0-20230220061748-93ff001f4a1d h1:cQ30Wa8mhLzK1TSOG+g3FlneIsXtFgun61mmPwVPmD0= github.com/bmc-toolbox/common v0.0.0-20230220061748-93ff001f4a1d/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= +github.com/cavaliergopher/grab v2.0.0+incompatible/go.mod h1:6ICNRTQPwkMP0m2sKIDv/9XkhFJJwiEOQyZ+8E4H7Yg= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= @@ -33,44 +113,102 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.5.0/go.mod h1:sPPkBS5L8l8sRc/IOO1jG51Xb34u+TYhL6P//JdODMQ= +github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= +github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +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/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= +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-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/yaml v0.0.0-20141224210557-6b16a5714269 h1:/1sjrpK5Mb6IwyFOKd+u7321tXfNAsj0Ci8CivZmSlo= +github.com/coreos/yaml v0.0.0-20141224210557-6b16a5714269/go.mod h1:Bl1D/T9QJhVdu6eFoLrGxN90+admDLGaLz2HXH/VzDc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/cli v20.10.14+incompatible h1:dSBKJOVesDgHo7rbxlYjYsXe7gPzrTT+/cKQgpDAazg= -github.com/docker/cli v20.10.14+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v20.10.14+incompatible h1:+T9/PRYWNDo5SZl5qS1r9Mo/0Q8AwxKKPtu9S1yxM0w= -github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/davidcassany/linuxkit/pkg/metadata v0.0.0-20210714125456-8b187a9ffd7e/go.mod h1:GIS28BxE1G2YB+dCf+O2Ow/bVP7hqioSWLsvr9YQg3o= +github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= +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/diskfs/go-diskfs v1.1.1/go.mod h1:afUPxxu+x1snp4aCY2bKR0CoZ/YFJewV3X2UEr2nPZE= +github.com/docker/cli v20.10.20+incompatible h1:lWQbHSHUFs7KraSN2jOJK7zbMS2jNCHI4mt4xUFUVQ4= +github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v17.12.0-ce-rc1.0.20200417035958-130b0bc6032c+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg= +github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +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/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libnetwork v0.8.0-dev.2.0.20200612180813-9e99af28df21/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +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= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-bindata/go-bindata/v3 v3.1.3 h1:F0nVttLC3ws0ojc7p60veTurcOm//D4QBODNM7EGrCI= github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= +github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +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-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-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 v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= @@ -79,68 +217,205 @@ github.com/go-logr/zerologr v1.2.3 h1:up5N9vcH9Xck3jJkXzgyOxozT14R47IyDODz8LM1KS github.com/go-logr/zerologr v1.2.3/go.mod h1:BxwGo7y5zgSHYR1BjbnHPyF/5ZjVKfKxAZANVu6E8Ho= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +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/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 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/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-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= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +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-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= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= 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.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/harvester/harvester-installer v1.3.0-rc4 h1:F1jaPsN/GrYft4H49QfgWdOuoREGKkUn2b+1PiM0MNU= +github.com/harvester/harvester-installer v1.3.0-rc4/go.mod h1:VFRNkozoe3N34fRbPI7Wsn1qVS5IPg4XRrUhigZetY0= github.com/harvester/webhook v0.1.4 h1:6g5MkYXlGm0wABQ/Dm8g5sM7WAtPq2aiWOH9wmf2vUQ= github.com/harvester/webhook v0.1.4/go.mod h1:vfRPB26WHSPxMF/ONpUVzaEaewTUxpP9qAqu1ZyonR0= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/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-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +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.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/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= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +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.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/ishidawataru/sctp v0.0.0-20191218070446-00ab2ac2db07/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= +github.com/itchyny/go-flags v1.5.0/go.mod h1:lenkYuCobuxLBAd/HGFE4LRoW8D3B6iXRQfWYJ+MNbA= +github.com/itchyny/gojq v0.12.2 h1:TxhFjk1w7Vnb0SwQPeG4FxTC98O4Es+x/mPaD5Azgfs= +github.com/itchyny/gojq v0.12.2/go.mod h1:mi4PdXSlFllHyByM68JKUrbiArtEdEnNEmjbwxcQKAg= +github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs= +github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A= github.com/jacobweinstock/iamt v0.0.0-20230502042727-d7cdbe67d9ef h1:G4k02HGmBUfJFSNu3gfKJ+ki+B3qutKsYzYndkqqKc4= github.com/jacobweinstock/iamt v0.0.0-20230502042727-d7cdbe67d9ef/go.mod h1:FgmiLTU6cJewV4Xgrq6m5o8CUlTQOJtqzaFLGA0mG+E= github.com/jacobweinstock/registrar v0.4.7 h1:s4dOExccgD+Pc7rJC+f3Mc3D+NXHcXUaOibtcEsPxOc= github.com/jacobweinstock/registrar v0.4.7/go.mod h1:PWmkdGFG5/ZdCqgMo7pvB3pXABOLHc5l8oQ0sgmBNDU= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 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 v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +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/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/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +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 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -148,62 +423,182 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.10 h1:Y7Xqm8piKOO3v10Thp7Z36h4FYFjt5xB//6XvOrs2Gw= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +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.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/libnetwork v0.8.0-dev.2.0.20200612180813-9e99af28df21/go.mod h1:RQTqDxGZChsPHosY8R3ZL2THYWUuW8X5SRhiBNoTY5I= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= 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= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +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/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/mudler/entities v0.0.0-20211108084227-d1414478861b/go.mod h1:qquFT9tYp+/NO7tTotto4BT9zSRYSMDxo2PGZwujpFA= +github.com/mudler/yip v0.0.0-20211129144714-088f39125cf7 h1:9yuv3CMIZx+Mt3Zj54Kpac42IAou5p7lQ6m2LLzNs6E= +github.com/mudler/yip v0.0.0-20211129144714-088f39125cf7/go.mod h1:ejqp/S2gmS9sh498Ib/B//k9GQvXX98EfeyIxxEkGIM= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= 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= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +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/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.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.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 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/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw= github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= +github.com/packethost/packngo v0.1.0/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/paultag/go-modprobe v0.0.0-20200930231701-46c7252028d3/go.mod h1:8kv7zKfUEDKENYA4Wk+cT1bxjXaEiuYisqjRZGGNI84= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +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= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/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.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rancher-sandbox/cloud-init v1.14.3-0.20210913085759-bf90bf5eb77e h1:1GSTIPu7CB2UCkS++2/wMygc3S+aa5O0VbTsdDrYupE= +github.com/rancher-sandbox/cloud-init v1.14.3-0.20210913085759-bf90bf5eb77e/go.mod h1:qbJr82AYxRKlEa4ZSm6qENOmXebBxPXne8BWbtll4cg= github.com/rancher/dynamiclistener v0.3.5 h1:5TaIHvkDGmZKvc96Huur16zfTKOiLhDtK4S+WV0JA6A= github.com/rancher/dynamiclistener v0.3.5/go.mod h1:dW/YF6/m2+uEyJ5VtEcd9THxda599HP6N9dSXk81+k0= github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc h1:29VHrInLV4qSevvcvhBj5UhQWkPShxrxv4AahYg2Scw= github.com/rancher/lasso v0.0.0-20221227210133-6ea88ca2fbcc/go.mod h1:dEfC9eFQigj95lv/JQ8K5e7+qQCacWs1aIA6nLxKzT8= +github.com/rancher/mapper v0.0.0-20190814232720-058a8b7feb99 h1:rGnt9h1Uk7Yw4qNPyGq0LWHGdPyag/+Fg/wJWSTkKx4= +github.com/rancher/mapper v0.0.0-20190814232720-058a8b7feb99/go.mod h1:zU4cm21k7ZBFVQhUu2aSH7NwouY317rLYxruOn+wdOQ= +github.com/rancher/wrangler v0.0.0-20190426050201-5946f0eaed19/go.mod h1:snD4YYjLOsxOwXNQORUkKr0y2TOVk54yWjgZ7myL8es= github.com/rancher/wrangler v1.1.1 h1:wmqUwqc2M7ADfXnBCJTFkTB5ZREWpD78rnZMzmxwMvM= github.com/rancher/wrangler v1.1.1/go.mod h1:ioVbKupzcBOdzsl55MvEDN0R1wdGggj8iNCYGFI5JvM= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= @@ -211,202 +606,713 @@ github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= 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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 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/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.0.3/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/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.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +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.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stmcginnis/gofish v0.14.1-0.20230920133920-77490fd98fa2 h1:R0N4G786trm1dHBwJftzaupRrwhY1T+rBrTBC8eqiRQ= github.com/stmcginnis/gofish v0.14.1-0.20230920133920-77490fd98fa2/go.mod h1:BLDSFTp8pDlf/xDbLZa+F7f7eW0E/CHCboggsu8CznI= 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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tinkerbell/rufio v0.3.2 h1:NNhDdMib6DC5be4cigMXQiY1r50k9i4KDnaAqTrCXuU= github.com/tinkerbell/rufio v0.3.2/go.mod h1:R58S818KbHn9RSeI4OwvbesgoAuS8v9ftHKG0qRtRBM= -github.com/tinkerbell/tink v0.6.1-0.20220524234633-0a800a4b5e25 h1:WrprXQjYOKWhVZWEFe3I6/ybHxwKGkCp+i8ZgJ8g1v0= -github.com/tinkerbell/tink v0.6.1-0.20220524234633-0a800a4b5e25/go.mod h1:px5E+SccP2xvZRnHHf8smb8vtKnroXXwx7lGg30igS8= +github.com/tinkerbell/tink v0.9.0 h1:W7X/OEmhyYXE/kPVu1U31fpugVHoc2qsAvBtsZ7mkDg= +github.com/tinkerbell/tink v0.9.0/go.mod h1:r8gDvx/Y+GEFeT9xwKa14ULrkMre8mYmH3/E9VbUkEw= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tredoe/osutil v1.5.0 h1:UGVxbbHRoZi8xXVmbNZ2vgG6XoJ15ndE4LniiQ3rJKg= +github.com/tredoe/osutil v1.5.0/go.mod h1:TEzphzUUunysbdDRfdOgqkg10POQbnfIPV50ynqOfIg= +github.com/tredoe/osutil/v2 v2.0.0-rc.16/go.mod h1:uLRVx/3pb7Y4RQhG8cQFbPE9ha5r81e6MXpBsxbTAYc= +github.com/twpayne/go-vfs v1.5.0 h1:3j9j2RchDSIQ1gjuNHZqJOyZAS702lrmqUow2uUYgX8= +github.com/twpayne/go-vfs v1.5.0/go.mod h1:MAbvpnWRAE5LfIt88Eopskigmyc+wakYCyCDnys7iNw= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY= github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/vishvananda/netlink v0.0.0-20170808154308-f5a6f697a596/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20170707011535-86bef332bfc3/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/willdonnelly/passwd v0.0.0-20141013001024-7935dab3074c/go.mod h1:xcvfY9pOw6s4wyrhilFSbMthL6KzgrfCIETHHUOQ/fQ= +github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zcalusic/sysinfo v0.0.0-20210831153053-2c6e1d254246/go.mod h1:WGLNaWsjKQ2gXmAHh+MQztgu3FLFAnOFJjFzhpgShCY= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20200513165325-16679db567ff/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4= +github.com/zmap/zcrypto v0.0.0-20200911161511-43ff0ea04f21/go.mod h1:TxpejqcVKQjQaVVmMGfzx5HnmFMdIU+vLtaCyPBfGI4= +github.com/zmap/zlint/v2 v2.2.1/go.mod h1:ixPWsdq8qLxYRpNUTbcKig3R7WgmspsHGLhCCs6rFAM= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +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= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6 h1:lGdhQUN/cnWdSH3291CUuxSEqc+AsGTiDxPP3r2J0l4= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 h1:WJhcL4p+YeDxmZWg141nRm7XC8IDmhz7lk5GpadO1Sg= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +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-20190219172222-a4c6cb3142f2/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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200124225646-8b5121be2f68/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230127130021-4ca2cb1a16b7 h1:o7Ps2IYdzLRolS9/nadqeMSHpa9k8pu8u+VKBFUG7cQ= golang.org/x/exp v0.0.0-20230127130021-4ca2cb1a16b7/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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-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-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-20190318221613-d196dffd7c2b/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= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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-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= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-20190402181905-9f3314589c9a/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= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-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-20190312061237-fead79001313/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-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-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/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= +golang.org/x/sys v0.0.0-20200102141924-c96a22e43c9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/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-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/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-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +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.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= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/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-20180917221912-90fa682c2a6e/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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190411180116-681f9ce8ac52/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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-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-20190816200558-6889da9d5479/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-20191012152004-8de300cfc20a/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= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +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= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +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= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +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-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-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= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +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= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= +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/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= 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.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +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/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +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= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/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.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= -inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 h1:acCzuUSQ79tGsM/O50VRFySfMm19IoMKL+sZztZkCxw= -inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6/go.mod h1:y3MGhcFMlh0KZPMuXXow8mpjxxAk3yoDNsp4cQz54i8= -k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +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= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +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= +inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a h1:1XCVEdxrvL6c0TGOhecLuB7U9zYNdxZEjvOqJreKZiM= +inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a/go.mod h1:e83i32mAQOW1LAqEIweALsuK2Uw4mhQadA5r7b0Wobo= +k8s.io/api v0.0.0-20190222213804-5cb15d344471/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= -k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= -k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= -k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= +k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= +k8s.io/apiextensions-apiserver v0.0.0-20190325193600-475668423e9f/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= +k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= +k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= +k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= +k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= -k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= -k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= +k8s.io/code-generator v0.0.0-20181117043124-c2090bec4d9b/go.mod h1:MYiN+ZJZ9HkETbgVZdWw2AsuAi9PZ4V80cwfuf2axe8= +k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= +k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= +k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= 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.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-aggregator v0.28.2 h1:tCjAfB1p/v18yD2NpegNQRuahzyA/szFfcRARnpjDeo= -k8s.io/kube-aggregator v0.28.2/go.mod h1:g4hZVjC4KhJtZHV2pyiRBiU6AdBA/sAjh9Y9GJC/SbU= +k8s.io/kube-aggregator v0.25.4 h1:QIeTa29I2a0VOFwZtpquz/bkNPk+dnUiDPbI/Vq7MbI= +k8s.io/kube-aggregator v0.25.4/go.mod h1:PH65mLSQoUld53w0VkdYcsIGh7wjJGZ5DyfoARronz0= +k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= -sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +pault.ag/go/topsort v0.0.0-20160530003732-f98d2ad46e1a/go.mod h1:INqx0ClF7kmPAMk2zVTX8DRnhZ/yaA/Mg52g8KFKE7k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU= +sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +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= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/api/v1alpha1/cluster_types.go b/pkg/api/v1alpha1/cluster_types.go index 8594b15..e8b1e3d 100644 --- a/pkg/api/v1alpha1/cluster_types.go +++ b/pkg/api/v1alpha1/cluster_types.go @@ -45,9 +45,17 @@ type VIPConfig struct { } type ClusterConfig struct { - ConfigURL string `json:"configURL,omitempty"` - SSHKeys []string `json:"sshKeys,omitempty"` - Nameservers []string `json:"nameservers,omitempty"` + ConfigURL string `json:"configURL,omitempty"` + SSHKeys []string `json:"sshKeys,omitempty"` + Nameservers []string `json:"nameservers,omitempty"` + CustomProvisioningTemplate string `json:"customProvisioningTemplate,omitempty"` + BondOptions map[string]string `json:"bondOptions,omitempty"` + // +kubebuilder:default=1 + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum4094 + VlanID int `json:"vlanID"` + StreamImageMode bool `json:"streamImageMode,omitempty"` + WipeDisks bool `json:"wipeDisks,omitempty"` } type NodeConfig struct { @@ -73,7 +81,7 @@ type ClusterWorkflowStatus string const ( ClusterConfigReady ClusterWorkflowStatus = "clusterConfigReady" ClusterNodesPatched ClusterWorkflowStatus = "clusterNodesPatched" - ClusterTinkHardwareSubmitted ClusterWorkflowStatus = "tinkHardwareCreated" + ClusterTinkHardwareSubmitted ClusterWorkflowStatus = "tinkConfigReady" ClusterRunning ClusterWorkflowStatus = "clusterRunning" ) diff --git a/pkg/api/v1alpha1/common.go b/pkg/api/v1alpha1/common.go index a8067b6..7375166 100644 --- a/pkg/api/v1alpha1/common.go +++ b/pkg/api/v1alpha1/common.go @@ -8,6 +8,7 @@ const ( OverrideAPIPortLabel = "clusterPort.harvesterhci.io" OverrideRedfishPortLabel = "redfishPort.harvesterhci.io" EventLoggerName = "HarvesterHardwareDiscovery" + WorkflowLoggerName = "WorkflowEvent" ) var ( @@ -15,9 +16,15 @@ var ( ) const ( - NodePowerActionShutdown = "shutdown" - NodePowerActionPowerOn = "poweron" - NodePowerActionReboot = "reboot" - NodeJobComplete = "complete" - NodeJobFailed = "failed" + NodePowerActionShutdown = "shutdown" + NodePowerActionPowerOn = "poweron" + NodePowerActionReboot = "reboot" + NodeJobComplete = "complete" + NodeJobFailed = "failed" + DefaultHarvesterProvisioningTemplate = "default-harvester-template" + DefaultTinkStackService = "tink-stack" + SeederConfig = "seeder-config" + DefaultEndpointPort = 9090 + DefaultSeederDeploymentService = "harvester-seeder-endpoint" + DefaultHegelDeploymentEndpointLookup = "smee" ) diff --git a/pkg/api/v1alpha1/inventory_types.go b/pkg/api/v1alpha1/inventory_types.go index f5d5870..efb8dc4 100644 --- a/pkg/api/v1alpha1/inventory_types.go +++ b/pkg/api/v1alpha1/inventory_types.go @@ -57,6 +57,8 @@ const ( HarvesterCreateNode condition.Cond = "harvesterCreateNode" HarvesterJoinNode condition.Cond = "harvesterJoinNode" MachineNotContactable condition.Cond = "machineNotContactable" + TinkHardwareCreated condition.Cond = "tinkHardwareCreated" + TinkTemplateCreated condition.Cond = "tinkTemplateCreated" ) // InventorySpec defines the desired state of Inventory @@ -66,6 +68,9 @@ type InventorySpec struct { BaseboardManagementSpec rufio.MachineSpec `json:"baseboardSpec"` Events `json:"events"` PowerActionRequested string `json:"powerActionRequested,omitempty"` + // +kubebuilder:default=amd64 + // +kubebuilder:validation:Enum=amd64;arm64 + Arch string `json:"arch,omitempty"` } type BMCSecretReference struct { diff --git a/pkg/api/v1alpha1/zz_generated.deepcopy.go b/pkg/api/v1alpha1/zz_generated.deepcopy.go index fd225d8..c43b320 100644 --- a/pkg/api/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/v1alpha1/zz_generated.deepcopy.go @@ -175,6 +175,13 @@ func (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.BondOptions != nil { + in, out := &in.BondOptions, &out.BondOptions + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfig. diff --git a/pkg/controllers/cluster_controller.go b/pkg/controllers/cluster_controller.go index 384bdc7..87a4f37 100644 --- a/pkg/controllers/cluster_controller.go +++ b/pkg/controllers/cluster_controller.go @@ -21,7 +21,9 @@ import ( "fmt" "github.com/go-logr/logr" - tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/rancher/wrangler/pkg/condition" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + 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" @@ -265,8 +267,22 @@ func (r *ClusterReconciler) patchNodesAndPools(ctx context.Context, cObj *seeder func (r *ClusterReconciler) createTinkerbellHardware(ctx context.Context, cObj *seederv1alpha1.Cluster) error { c := cObj.DeepCopy() if c.Status.Status == seederv1alpha1.ClusterNodesPatched || c.Status.Status == seederv1alpha1.ClusterTinkHardwareSubmitted || c.Status.Status == seederv1alpha1.ClusterRunning { + + // check to see if the service for tink-stack is ready + tinkStackService := &corev1.Service{} + err := r.Get(ctx, types.NamespacedName{Name: seederv1alpha1.DefaultTinkStackService, Namespace: deploymentNamespace}, tinkStackService) + if err != nil { + return fmt.Errorf("error fetching svc %s in ns %s: %v", seederv1alpha1.DefaultTinkStackService, seederv1alpha1.DefaultLocalClusterNamespace, err) + } + + seederDeploymentService := &corev1.Service{} + err = r.Get(ctx, types.NamespacedName{Name: seederv1alpha1.DefaultSeederDeploymentService, Namespace: deploymentNamespace}, seederDeploymentService) + + if err != nil { + return fmt.Errorf("error fetching svc %s in ns %s: %v", seederv1alpha1.DefaultSeederDeploymentService, seederv1alpha1.DefaultLocalClusterNamespace, err) + } + for _, i := range c.Spec.Nodes { - var hardwareUpdated bool inventory := &seederv1alpha1.Inventory{} err := r.Get(ctx, types.NamespacedName{Namespace: i.InventoryReference.Namespace, Name: i.InventoryReference.Name}, inventory) if err != nil { @@ -281,7 +297,9 @@ func (r *ClusterReconciler) createTinkerbellHardware(ctx context.Context, cObj * continue } - hw, err := tink.GenerateHWRequest(inventory, c) + // tinkStack Service exposes Hegel endpoint + // seederDeploymentService exposes the api endpoint to update hardware objects + hw, err := tink.GenerateHWRequest(inventory, c, seederDeploymentService, tinkStackService) if err != nil { return err } @@ -292,35 +310,14 @@ func (r *ClusterReconciler) createTinkerbellHardware(ctx context.Context, cObj * } // create / update hardware object if one already exists - lookupHw := &tinkv1alpha1.Hardware{} - err = r.Get(ctx, types.NamespacedName{Namespace: hw.Namespace, Name: hw.Name}, lookupHw) - + err = r.createOrUpdateHardware(ctx, hw, inventory) if err != nil { - if apierrors.IsNotFound(err) { - if err := r.Create(ctx, hw); err != nil { - return err - } - hardwareUpdated = true - } else { - return err - } - } - - if hardwareUpdated { - util.CreateOrUpdateCondition(inventory, seederv1alpha1.TinkWorkflowCreated, "tink workflow created") - if err := r.Status().Update(ctx, inventory); err != nil { - return err - } + return err } } } - if c.Status.Status == seederv1alpha1.ClusterNodesPatched { - c.Status.Status = seederv1alpha1.ClusterTinkHardwareSubmitted - return r.Status().Update(ctx, c) - } - return nil } @@ -378,24 +375,62 @@ func (r *ClusterReconciler) reconcileNodes(ctx context.Context, cObj *seederv1al iObj.Status.Cluster = seederv1alpha1.ObjectReference{} iObj.Status.GeneratedPassword = "" util.RemoveCondition(iObj, seederv1alpha1.InventoryAllocatedToCluster) - util.RemoveCondition(iObj, seederv1alpha1.TinkWorkflowCreated) + util.RemoveCondition(iObj, seederv1alpha1.TinkHardwareCreated) util.RemoveCondition(iObj, seederv1alpha1.HarvesterJoinNode) + util.RemoveCondition(iObj, seederv1alpha1.TinkWorkflowCreated) + util.RemoveCondition(iObj, seederv1alpha1.TinkTemplateCreated) util.CreateOrUpdateCondition(iObj, seederv1alpha1.InventoryFreed, "") if err := r.Status().Update(ctx, iObj); err != nil { return err } + var notFound bool // find and clean up hardware object hw := &tinkv1alpha1.Hardware{} if err := r.Get(ctx, types.NamespacedName{Namespace: iObj.Namespace, Name: iObj.Name}, hw); err != nil { if apierrors.IsNotFound(err) { - continue + notFound = true } else { return err } } - if err := r.Delete(ctx, hw); err != nil { - return err + + if !notFound { + if err := r.Delete(ctx, hw); err != nil { + return err + } + } + + // find and clean up template object + template := &tinkv1alpha1.Template{} + if err := r.Get(ctx, types.NamespacedName{Namespace: iObj.Namespace, Name: iObj.Name}, template); err != nil { + if apierrors.IsNotFound(err) { + notFound = true + } else { + return err + } + } + + if !notFound { + if err := r.Delete(ctx, template); err != nil { + return err + } + } + + // find and clean up workflow object + workflow := &tinkv1alpha1.Workflow{} + if err := r.Get(ctx, types.NamespacedName{Namespace: iObj.Namespace, Name: iObj.Name}, workflow); err != nil { + if apierrors.IsNotFound(err) { + notFound = true + } else { + return err + } + } + + if !notFound { + if err := r.Delete(ctx, workflow); err != nil { + return err + } } } @@ -461,6 +496,7 @@ func (r *ClusterReconciler) cleanupClusterDeps(ctx context.Context, cObj *seeder i.Status.PXEBootInterface = seederv1alpha1.PXEBootInterface{} i.Status.Cluster = seederv1alpha1.ObjectReference{} i.Status.GeneratedPassword = "" + i.Status.PowerAction = seederv1alpha1.PowerActionDetails{} util.RemoveCondition(i, seederv1alpha1.InventoryAllocatedToCluster) util.RemoveCondition(i, seederv1alpha1.HarvesterJoinNode) util.RemoveCondition(i, seederv1alpha1.HarvesterCreateNode) @@ -521,8 +557,8 @@ func (r *ClusterReconciler) markClusterReady(ctx context.Context, cObj *seederv1 return err } - if len(nl.Items) < 1 { - return fmt.Errorf("api server is running but waiting for one of the nodes to be available") + if len(nl.Items) != len(c.Spec.Nodes) { + return fmt.Errorf("api server is running, expected to find %d nodes but only found %d nodes", len(nl.Items), len(c.Spec.Nodes)) } c.Status.Status = seederv1alpha1.ClusterRunning @@ -589,3 +625,34 @@ func genCoreTypedClient(ctx context.Context, c *seederv1alpha1.Cluster) (*typedC return typedCore.NewForConfig(restConfig) } + +func createOrUpdateInventoryConditions(ctx context.Context, inventory *seederv1alpha1.Inventory, cond condition.Cond, msg string, client client.Client) error { + iObj := &seederv1alpha1.Inventory{} + if err := client.Get(ctx, types.NamespacedName{Name: inventory.Name, Namespace: inventory.Namespace}, iObj); err != nil { + return err + } + + if !util.ConditionExists(iObj, cond) { + util.CreateOrUpdateCondition(iObj, cond, msg) + if err := client.Status().Update(ctx, iObj); err != nil { + return err + } + } + + return nil +} + +func (r *ClusterReconciler) createOrUpdateHardware(ctx context.Context, hardware *tinkv1alpha1.Hardware, inventory *seederv1alpha1.Inventory) error { + hardwareObj := &tinkv1alpha1.Hardware{} + err := r.Get(ctx, types.NamespacedName{Name: hardware.Name, Namespace: hardware.Namespace}, hardwareObj) + if err != nil { + if apierrors.IsNotFound(err) { + if createErr := r.Create(ctx, hardware); createErr != nil { + return createErr + } + } + return err + } + + return createOrUpdateInventoryConditions(ctx, inventory, seederv1alpha1.TinkHardwareCreated, "tink hardware created", r.Client) +} diff --git a/pkg/controllers/cluster_controller_test.go b/pkg/controllers/cluster_controller_test.go index 4acf613..4270053 100644 --- a/pkg/controllers/cluster_controller_test.go +++ b/pkg/controllers/cluster_controller_test.go @@ -6,7 +6,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" rufio "github.com/tinkerbell/rufio/api/v1alpha1" - tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -97,7 +97,7 @@ var _ = Describe("Create cluster tests", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } @@ -150,16 +150,26 @@ var _ = Describe("Create cluster tests", func() { if !util.ConditionExists(tmpInventory, seederv1alpha1.InventoryAllocatedToCluster) { return fmt.Errorf("expected inventory to be allocated to cluster %v", tmpInventory.Status) } + // is tinkerbell hardware condition present + if !util.ConditionExists(tmpInventory, seederv1alpha1.TinkHardwareCreated) { + return fmt.Errorf("expected tinkerbell hardware condition to exist %v", tmpInventory.Status.Conditions) + } + + // is tinkerbell template condition present + if !util.ConditionExists(tmpInventory, seederv1alpha1.TinkTemplateCreated) { + return fmt.Errorf("expected tinkerbell template condition to exist %v", tmpInventory.Status.Conditions) + } + // is tinkerbell workflow condition present if !util.ConditionExists(tmpInventory, seederv1alpha1.TinkWorkflowCreated) { - return fmt.Errorf("expected tinkerbell hardware condition to exist %v", tmpInventory.Status.Conditions) + return fmt.Errorf("expected tinkerbell workflow condition to exist %v", tmpInventory.Status.Conditions) } if tmpInventory.Status.PowerAction.LastActionStatus != seederv1alpha1.NodeJobComplete { return fmt.Errorf("expected power action to be completed but got %s", tmpInventory.Status.PowerAction.LastActionStatus) } return nil - }, "30s", "5s").ShouldNot(HaveOccurred()) + }, "60s", "5s").ShouldNot(HaveOccurred()) }) It("reconcile hardware workflow in cluster controller reconcile", func() { @@ -188,6 +198,57 @@ var _ = Describe("Create cluster tests", func() { }, "30s", "5s").ShouldNot(HaveOccurred()) }) + It("reconcile tinkerbell template in cluster controller reconcile", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted") + } + + templateList := &tinkv1alpha1.TemplateList{} + if err := k8sClient.List(ctx, templateList, &client.ListOptions{Namespace: "default"}); err != nil { + return err + } + + for _, v := range templateList.Items { + if v.Name == i.Name && v.Namespace == i.Namespace { + return nil + } + } + + return fmt.Errorf("did not find workflow matching the inventory %s", i.Name) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("reconcile tinkerbell workflow in cluster controller reconcile", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted") + } + + workflowList := &tinkv1alpha1.WorkflowList{} + if err := k8sClient.List(ctx, workflowList, &client.ListOptions{Namespace: "default"}); err != nil { + return err + } + + for _, v := range workflowList.Items { + if v.Name == i.Name && v.Namespace == i.Namespace { + return nil + } + } + + return fmt.Errorf("did not find workflow matching the inventory %s", i.Name) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) // check cluster deletion and reconcilliation of hardware and inventory objects // Test is flaky when using TestEnv. Disabling for now It("delete cluster and check cleanup of inventory objects", func() { @@ -365,7 +426,7 @@ var _ = Describe("add inventory to cluster tests", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } @@ -611,7 +672,7 @@ var _ = Describe("delete inventory from cluster tests", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } @@ -835,7 +896,7 @@ var _ = Describe("cluster running test", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } @@ -1094,7 +1155,7 @@ var _ = Describe("multi-node cluster provisioning test", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } diff --git a/pkg/controllers/cluster_events_controller_test.go b/pkg/controllers/cluster_events_controller_test.go index 770f1ec..5d97075 100644 --- a/pkg/controllers/cluster_events_controller_test.go +++ b/pkg/controllers/cluster_events_controller_test.go @@ -113,7 +113,7 @@ var _ = Describe("cluster events test", func() { "abc", "def", }, - ConfigURL: "localhost:30300/config.yaml", + ConfigURL: "file:///testdata/config.yaml", }, }, } diff --git a/pkg/controllers/cluster_tinkerbell_template_controller.go b/pkg/controllers/cluster_tinkerbell_template_controller.go new file mode 100644 index 0000000..6cd59d4 --- /dev/null +++ b/pkg/controllers/cluster_tinkerbell_template_controller.go @@ -0,0 +1,207 @@ +package controllers + +import ( + "context" + "fmt" + "reflect" + + "github.com/go-logr/logr" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" + "github.com/harvester/seeder/pkg/tink" + "github.com/harvester/seeder/pkg/util" +) + +// ClusterTinkerbellTemplateReconciler reconciles a Cluster object and watches associated TinkerbellTemplate for changes +type ClusterTinkerbellTemplateReconciler struct { + client.Client + Scheme *runtime.Scheme + logr.Logger +} + +func (r *ClusterTinkerbellTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Info("Reconcilling inventory objects", req.Name, req.Namespace) + // TODO(user): your logic here + cObj := &seederv1alpha1.Cluster{} + + err := r.Get(ctx, req.NamespacedName, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + r.Error(err, "unable to fetch cluster object") + return ctrl.Result{}, err + } + + c := cObj.DeepCopy() + + // ignore the local cluster + if c.Name == seederv1alpha1.DefaultLocalClusterName && c.Namespace == seederv1alpha1.DefaultLocalClusterNamespace { + return ctrl.Result{}, nil + } + + reconcileList := []clusterReconciler{ + r.createTinkerbellTemplate, + } + + if c.DeletionTimestamp.IsZero() { + for _, reconciler := range reconcileList { + if err := reconciler(ctx, c); err != nil { + return ctrl.Result{}, err + } + } + } + + return ctrl.Result{}, nil +} + +// createTinkerbellTemplate will create template objects for all nodes in the cluster +func (r *ClusterTinkerbellTemplateReconciler) createTinkerbellTemplate(ctx context.Context, cObj *seederv1alpha1.Cluster) error { + + c := cObj.DeepCopy() + if c.Status.Status == seederv1alpha1.ClusterNodesPatched || c.Status.Status == seederv1alpha1.ClusterTinkHardwareSubmitted || c.Status.Status == seederv1alpha1.ClusterRunning { + // check to see if the service for tink-stack is ready + // if using an external tinkerbell stack this service should be ready as HegelEndpoint is used for serving harvester config via userdata on hardware object + // if using the custom tinkerbell chart in seeder repo, then tink-stack is not deployed but an nginx server is deployed + // to run with smee/boots, and this serves as a proxy to hegel endpoint, and we should switch to the same + hegelEndpoint, err := r.fetchHegelEndpoint(ctx) + if err != nil { + return fmt.Errorf("fetching hegel endpoint: %v", err) + } + + seederConfig := &corev1.ConfigMap{} + err = r.Get(ctx, types.NamespacedName{Name: seederv1alpha1.SeederConfig, Namespace: c.Namespace}, seederConfig) + if err != nil && !apierrors.IsNotFound(err) { + return fmt.Errorf("error fetching configmap %s in ns %s: %v", seederv1alpha1.SeederConfig, c.Namespace, err) + } + + for _, i := range c.Spec.Nodes { + inventory := &seederv1alpha1.Inventory{} + err := r.Get(ctx, types.NamespacedName{Namespace: i.InventoryReference.Namespace, Name: i.InventoryReference.Name}, inventory) + if err != nil { + return err + } + + // if node is missing inventory allocation to cluster + // then skip the HW generation, as this node doesnt yet have any addresses + // allocated + if !util.ConditionExists(inventory, seederv1alpha1.InventoryAllocatedToCluster) { + r.Info("skipping node from hardware generation as it has not yet been processed for allocation to cluster", inventory.Name, inventory.Namespace) + continue + } + + template, err := tink.GenerateTemplate(hegelEndpoint, seederConfig, inventory, c) + if err != nil { + return err + } + // create hardware object + err = controllerutil.SetOwnerReference(c, template, r.Scheme) + if err != nil { + return err + } + + // create / update hardware object if one already exists + err = r.createOrUpdateTemplate(ctx, template, inventory) + if err != nil { + return err + } + } + + } + + return nil +} + +// createOrUpdateTemplate will create or update the tinkerbell Template +func (r *ClusterTinkerbellTemplateReconciler) createOrUpdateTemplate(ctx context.Context, template *tinkv1alpha1.Template, inventory *seederv1alpha1.Inventory) error { + templateObj := &tinkv1alpha1.Template{} + err := r.Get(ctx, types.NamespacedName{Name: template.Name, Namespace: template.Namespace}, templateObj) + if err != nil { + if apierrors.IsNotFound(err) { + if createErr := r.Create(ctx, template); createErr != nil { + return createErr + } + } + return err + } + + if !reflect.DeepEqual(templateObj.Spec, template.Spec) { + templateObj.Spec = template.Spec + if err := r.Update(ctx, templateObj); err != nil { + return err + } + } + + return createOrUpdateInventoryConditions(ctx, inventory, seederv1alpha1.TinkTemplateCreated, "tink template created", r.Client) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterTinkerbellTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&seederv1alpha1.Cluster{}). + Watches(&tinkv1alpha1.Template{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request { + var reconRequest []reconcile.Request + owners := a.GetOwnerReferences() + for _, o := range owners { + if o.Kind == "Cluster" && o.APIVersion == "metal.harvesterhci.io/v1alpha1" { + reconRequest = append(reconRequest, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: a.GetNamespace(), + Name: o.Name, + }, + }) + } + } + return reconRequest + })). + Complete(r) +} + +func (r *ClusterTinkerbellTemplateReconciler) fetchHegelEndpoint(ctx context.Context) (string, error) { + // check to see if the service for tink-stack is ready + // if using an external tinkerbell stack this service should be ready as HegelEndpoint is used for serving harvester config via userdata on hardware object + // if using the custom tinkerbell chart in seeder repo, then tink-stack is not deployed but an nginx server is deployed + // to run with smee/boots, and this serves as a proxy to hegel endpoint, and we should switch to the same + tinkStackService := &corev1.Service{} + err := r.Get(ctx, types.NamespacedName{Name: seederv1alpha1.DefaultTinkStackService, Namespace: deploymentNamespace}, tinkStackService) + + if err != nil { + if !apierrors.IsNotFound(err) { + return "", fmt.Errorf("error fetching svc %s in ns %s: %v", seederv1alpha1.DefaultTinkStackService, deploymentNamespace, err) + } + } else { + return tinkStackService.Status.LoadBalancer.Ingress[0].IP, nil + } + + // lookup smee pod address + podList := &corev1.PodList{} + ls := labels.SelectorFromSet(map[string]string{ + "app": seederv1alpha1.DefaultHegelDeploymentEndpointLookup, + "stack": "tinkerbell", + }) + err = r.List(ctx, podList, &client.ListOptions{ + LabelSelector: ls, + Namespace: deploymentNamespace, + }) + + if err != nil { + return "nil", err + } + + if len(podList.Items) == 0 { + return "", fmt.Errorf("no pods matching smee requirements found") + } + return podList.Items[0].Status.HostIP, nil + +} diff --git a/pkg/controllers/cluster_tinkerbell_template_controller_test.go b/pkg/controllers/cluster_tinkerbell_template_controller_test.go new file mode 100644 index 0000000..0a4197e --- /dev/null +++ b/pkg/controllers/cluster_tinkerbell_template_controller_test.go @@ -0,0 +1,200 @@ +package controllers + +import ( + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + v1 "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" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +var _ = Describe("reconcile tinkerbell template deletion test", func() { + var i *seederv1alpha1.Inventory + var c *seederv1alpha1.Cluster + var a *seederv1alpha1.AddressPool + var creds *v1.Secret + BeforeEach(func() { + a = &seederv1alpha1.AddressPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-template-test", + Namespace: "default", + }, + Spec: seederv1alpha1.AddressSpec{ + CIDR: "192.168.1.1/29", + Gateway: "192.168.1.7", + }, + } + + i = &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-template-test", + Namespace: "default", + }, + Spec: seederv1alpha1.InventorySpec{ + PrimaryDisk: "/dev/sda", + ManagementInterfaceMacAddress: "xx:xx:xx:xx:xx", + BaseboardManagementSpec: rufio.MachineSpec{ + Connection: rufio.Connection{ + Host: "localhost", + Port: 623, + InsecureTLS: true, + AuthSecretRef: v1.SecretReference{ + Name: "cluster-template-test", + Namespace: "default", + }, + }, + }, + }, + } + + creds = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-template-test", + Namespace: "default", + }, + StringData: map[string]string{ + "username": "admin", + "password": "password", + }, + } + + c = &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-template-test", + Namespace: "default", + }, + Spec: seederv1alpha1.ClusterSpec{ + HarvesterVersion: "harvester_1_0_2", + Nodes: []seederv1alpha1.NodeConfig{ + { + InventoryReference: seederv1alpha1.ObjectReference{ + Name: "cluster-template-test", + Namespace: "default", + }, + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "cluster-template-test", + Namespace: "default", + }, + }, + }, + VIPConfig: seederv1alpha1.VIPConfig{ + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "cluster-template-test", + Namespace: "default", + }, + }, + ClusterConfig: seederv1alpha1.ClusterConfig{ + SSHKeys: []string{ + "abc", + "def", + }, + ConfigURL: "file:///testdata/config.yaml", + }, + }, + } + + Eventually(func() error { + return k8sClient.Create(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure cluster status is ClusterTinkHardwareSubmitted", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted") + } + + return nil + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure template object exists", func() { + Eventually(func() error { + templateObj := &tinkv1alpha1.Template{} + return k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, templateObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("delete template object", func() { + Eventually(func() error { + templateObj := &tinkv1alpha1.Template{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, templateObj); err != nil { + return err + } + + return k8sClient.Delete(ctx, templateObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure template object is recreated", func() { + Eventually(func() error { + templateObj := &tinkv1alpha1.Template{} + return k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, templateObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + + Eventually(func() error { + // check and delete cluster if needed. Need this since one of the tests simulates removing cluster + // and checking gc of hardware objects + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + return k8sClient.Delete(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + Eventually(func() error { + return k8sClient.Delete(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + return fmt.Errorf("waiting for cluster finalizers to finish") + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) +}) diff --git a/pkg/controllers/cluster_tinkerbell_workflow_controller.go b/pkg/controllers/cluster_tinkerbell_workflow_controller.go new file mode 100644 index 0000000..51cbace --- /dev/null +++ b/pkg/controllers/cluster_tinkerbell_workflow_controller.go @@ -0,0 +1,165 @@ +package controllers + +import ( + "context" + "reflect" + + "github.com/go-logr/logr" + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" + "github.com/harvester/seeder/pkg/tink" + "github.com/harvester/seeder/pkg/util" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +// ClusterTinkerbellWorkflowReconciler reconciles a Cluster object and watches associated TinkerbellTemplate for changes +type ClusterTinkerbellWorkflowReconciler struct { + client.Client + Scheme *runtime.Scheme + logr.Logger +} + +func (r *ClusterTinkerbellWorkflowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Info("Reconcilling inventory objects", req.Name, req.Namespace) + // TODO(user): your logic here + cObj := &seederv1alpha1.Cluster{} + + err := r.Get(ctx, req.NamespacedName, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + r.Error(err, "unable to fetch cluster object") + return ctrl.Result{}, err + } + + c := cObj.DeepCopy() + + // ignore the local cluster + if c.Name == seederv1alpha1.DefaultLocalClusterName && c.Namespace == seederv1alpha1.DefaultLocalClusterNamespace { + return ctrl.Result{}, nil + } + + reconcileList := []clusterReconciler{ + r.createTinkerbellWorkflow, + } + + if c.DeletionTimestamp.IsZero() { + for _, reconciler := range reconcileList { + if err := reconciler(ctx, c); err != nil { + return ctrl.Result{}, err + } + } + } + + return ctrl.Result{}, nil +} + +// createTinkerbellWorkflow will create workflow objects for all nodes in the cluster +func (r *ClusterTinkerbellWorkflowReconciler) createTinkerbellWorkflow(ctx context.Context, cObj *seederv1alpha1.Cluster) error { + + c := cObj.DeepCopy() + if c.Status.Status == seederv1alpha1.ClusterNodesPatched || c.Status.Status == seederv1alpha1.ClusterTinkHardwareSubmitted || c.Status.Status == seederv1alpha1.ClusterRunning { + for _, i := range c.Spec.Nodes { + inventory := &seederv1alpha1.Inventory{} + err := r.Get(ctx, types.NamespacedName{Namespace: i.InventoryReference.Namespace, Name: i.InventoryReference.Name}, inventory) + if err != nil { + return err + } + + // if node is missing inventory allocation to cluster + // then skip the HW generation, as this node doesnt yet have any addresses + // allocated + if !util.ConditionExists(inventory, seederv1alpha1.InventoryAllocatedToCluster) { + r.Info("skipping node from hardware generation as it has not yet been processed for allocation to cluster", inventory.Name, inventory.Namespace) + continue + } + + workflow := tink.GenerateWorkflow(inventory, c) + if err != nil { + return err + } + // create hardware object + err = controllerutil.SetOwnerReference(c, workflow, r.Scheme) + if err != nil { + return err + } + + err = r.createOrUpdateWorkflow(ctx, workflow, inventory) + if err != nil { + return err + } + } + + } + + // check all inventory objects have correct conditions before updating cluster object + conditionsPresent := true + for _, v := range c.Spec.Nodes { + iObj := &seederv1alpha1.Inventory{} + if err := r.Get(ctx, types.NamespacedName{Name: v.InventoryReference.Name, Namespace: v.InventoryReference.Namespace}, iObj); err != nil { + return err + } + if !util.ConditionExists(iObj, seederv1alpha1.TinkHardwareCreated) || !util.ConditionExists(iObj, seederv1alpha1.TinkTemplateCreated) || !util.ConditionExists(iObj, seederv1alpha1.TinkWorkflowCreated) { + conditionsPresent = conditionsPresent && false + } + } + + if c.Status.Status == seederv1alpha1.ClusterNodesPatched { + c.Status.Status = seederv1alpha1.ClusterTinkHardwareSubmitted + return r.Status().Update(ctx, c) + } + + return nil +} + +func (r *ClusterTinkerbellWorkflowReconciler) createOrUpdateWorkflow(ctx context.Context, wf *tinkv1alpha1.Workflow, inventory *seederv1alpha1.Inventory) error { + wfObj := &tinkv1alpha1.Workflow{} + err := r.Get(ctx, types.NamespacedName{Name: wf.Name, Namespace: wf.Namespace}, wfObj) + if err != nil { + if apierrors.IsNotFound(err) { + if createErr := r.Create(ctx, wf); createErr != nil { + return createErr + } + } + return err + } + + if !reflect.DeepEqual(wfObj.Spec, wf.Spec) { + wfObj.Spec = wf.Spec + if err := r.Update(ctx, wfObj); err != nil { + return err + } + } + + return createOrUpdateInventoryConditions(ctx, inventory, seederv1alpha1.TinkWorkflowCreated, "tink workflow created", r.Client) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ClusterTinkerbellWorkflowReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&seederv1alpha1.Cluster{}). + Watches(&tinkv1alpha1.Workflow{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a client.Object) []reconcile.Request { + var reconRequest []reconcile.Request + owners := a.GetOwnerReferences() + for _, o := range owners { + if o.Kind == "Cluster" && o.APIVersion == "metal.harvesterhci.io/v1alpha1" { + reconRequest = append(reconRequest, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: a.GetNamespace(), + Name: o.Name, + }, + }) + } + } + return reconRequest + })). + Complete(r) +} diff --git a/pkg/controllers/cluster_tinkerbell_workflow_controller_test.go b/pkg/controllers/cluster_tinkerbell_workflow_controller_test.go new file mode 100644 index 0000000..72fb271 --- /dev/null +++ b/pkg/controllers/cluster_tinkerbell_workflow_controller_test.go @@ -0,0 +1,200 @@ +package controllers + +import ( + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + v1 "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" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +var _ = Describe("reconcile tinkerbell workflow deletion test", func() { + var i *seederv1alpha1.Inventory + var c *seederv1alpha1.Cluster + var a *seederv1alpha1.AddressPool + var creds *v1.Secret + BeforeEach(func() { + a = &seederv1alpha1.AddressPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + Spec: seederv1alpha1.AddressSpec{ + CIDR: "192.168.1.1/29", + Gateway: "192.168.1.7", + }, + } + + i = &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + Spec: seederv1alpha1.InventorySpec{ + PrimaryDisk: "/dev/sda", + ManagementInterfaceMacAddress: "xx:xx:xx:xx:xx", + BaseboardManagementSpec: rufio.MachineSpec{ + Connection: rufio.Connection{ + Host: "localhost", + Port: 623, + InsecureTLS: true, + AuthSecretRef: v1.SecretReference{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + }, + }, + }, + } + + creds = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + StringData: map[string]string{ + "username": "admin", + "password": "password", + }, + } + + c = &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + Spec: seederv1alpha1.ClusterSpec{ + HarvesterVersion: "harvester_1_0_2", + Nodes: []seederv1alpha1.NodeConfig{ + { + InventoryReference: seederv1alpha1.ObjectReference{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + }, + }, + VIPConfig: seederv1alpha1.VIPConfig{ + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "cluster-workflow-test", + Namespace: "default", + }, + }, + ClusterConfig: seederv1alpha1.ClusterConfig{ + SSHKeys: []string{ + "abc", + "def", + }, + ConfigURL: "file:///testdata/config.yaml", + }, + }, + } + + Eventually(func() error { + return k8sClient.Create(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure cluster status is ClusterTinkHardwareSubmitted", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted") + } + + return nil + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure workflow object exists", func() { + Eventually(func() error { + workflowObj := &tinkv1alpha1.Workflow{} + return k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, workflowObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("delete workflow object", func() { + Eventually(func() error { + workflowObj := &tinkv1alpha1.Workflow{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, workflowObj); err != nil { + return err + } + + return k8sClient.Delete(ctx, workflowObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("ensure workflow object is recreated", func() { + Eventually(func() error { + workflowObj := &tinkv1alpha1.Workflow{} + return k8sClient.Get(ctx, types.NamespacedName{Namespace: i.Namespace, Name: i.Name}, workflowObj) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + + Eventually(func() error { + // check and delete cluster if needed. Need this since one of the tests simulates removing cluster + // and checking gc of hardware objects + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + return k8sClient.Delete(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + Eventually(func() error { + return k8sClient.Delete(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + return fmt.Errorf("waiting for cluster finalizers to finish") + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) +}) diff --git a/pkg/controllers/inventory_controller.go b/pkg/controllers/inventory_controller.go index 88a2786..9afad25 100644 --- a/pkg/controllers/inventory_controller.go +++ b/pkg/controllers/inventory_controller.go @@ -254,10 +254,17 @@ func (r *InventoryReconciler) triggerReboot(ctx context.Context, iObj *seederv1a // if tink hardware has been created and inventory is allocated to a cluster // then reboot the hardware using BMC tasks i := iObj.DeepCopy() - if i.Status.Status == seederv1alpha1.InventoryReady && util.ConditionExists(i, seederv1alpha1.TinkWorkflowCreated) && util.ConditionExists(i, seederv1alpha1.InventoryAllocatedToCluster) && !util.ConditionExists(i, seederv1alpha1.BMCJobSubmitted) { + // TODO: Change it back to check seederv1alpha1.TinkWorkflowCreated exists since this will be a valid condition after move to + // workflow based processing + if i.Status.Status == seederv1alpha1.InventoryReady && util.ConditionExists(i, seederv1alpha1.TinkHardwareCreated) && util.ConditionExists(i, seederv1alpha1.InventoryAllocatedToCluster) && !util.ConditionExists(i, seederv1alpha1.BMCJobSubmitted) && i.Status.PowerAction.LastJobName == "" { // submit BMC task - i.Spec.PowerActionRequested = seederv1alpha1.NodePowerActionReboot - return r.Update(ctx, i) + j := util.GenerateJob(i.Name, i.Namespace, "reboot") + if err := r.jobWrapper(ctx, i, j); err != nil { + return err + } + util.CreateOrUpdateCondition(i, seederv1alpha1.BMCJobSubmitted, "BMCJob Submitted") + i.Status.PowerAction.LastJobName = j.Name + return r.Status().Update(ctx, i) } return nil @@ -306,27 +313,9 @@ func (r *InventoryReconciler) reconcileBMCJob(ctx context.Context, iObj *seederv func (r *InventoryReconciler) inventoryFreed(ctx context.Context, iObj *seederv1alpha1.Inventory) error { i := iObj.DeepCopy() if util.ConditionExists(i, seederv1alpha1.InventoryFreed) { - // check and submit a power off job - var notFound bool - j := util.GenerateJob(i.Name, i.Namespace, "shutdown") - jobObj := &rufio.Job{} - err := r.Get(ctx, types.NamespacedName{Namespace: j.Namespace, Name: j.Name}, jobObj) - if err != nil { - if apierrors.IsNotFound(err) { - notFound = true - } else { - return err - } - } - - if notFound { - if err := controllerutil.SetOwnerReference(i, j, r.Scheme); err != nil { - return err - } - if err := r.Create(ctx, j); err != nil { - return err - } + if err := r.jobWrapper(ctx, i, j); err != nil { + return err } // trigger status update @@ -433,3 +422,26 @@ func (r *InventoryReconciler) checkAndResetInventory(ctx context.Context, iObj * } return nil } + +func (r *InventoryReconciler) jobWrapper(ctx context.Context, i *seederv1alpha1.Inventory, j *rufio.Job) error { + var notFound bool + jobObj := &rufio.Job{} + err := r.Get(ctx, types.NamespacedName{Namespace: j.Namespace, Name: j.Name}, jobObj) + if err != nil { + if apierrors.IsNotFound(err) { + notFound = true + } else { + return err + } + } + + if notFound { + if err := controllerutil.SetOwnerReference(i, j, r.Scheme); err != nil { + return err + } + if err := r.Create(ctx, j); err != nil { + return err + } + } + return nil +} diff --git a/pkg/controllers/local_cluster_controller_test.go b/pkg/controllers/local_cluster_controller_test.go index 44bd500..ad63456 100644 --- a/pkg/controllers/local_cluster_controller_test.go +++ b/pkg/controllers/local_cluster_controller_test.go @@ -1,7 +1,6 @@ package controllers import ( - "context" "fmt" "reflect" @@ -12,7 +11,6 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" @@ -129,10 +127,6 @@ var _ = Describe("Create and run local cluster tests", func() { }, } - Eventually(func() error { - return createHarvesterNamespace(ctx, k8sClient) - }, "30s", "5s").ShouldNot(HaveOccurred()) - Eventually(func() error { return util.SetupLocalCluster(ctx, k8sClient) }, "30s", "5s").ShouldNot(HaveOccurred()) @@ -344,19 +338,3 @@ var _ = Describe("Create and run local cluster tests", func() { }, "30s", "5s").ShouldNot(HaveOccurred()) }) }) - -func createHarvesterNamespace(ctx context.Context, k8sClient client.Client) error { - ns := &corev1.Namespace{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: "harvester-system", Namespace: ""}, ns) - if err != nil { - if apierrors.IsNotFound(err) { - ns := &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "harvester-system", - }, - } - return k8sClient.Create(ctx, ns) - } - } - return err -} diff --git a/pkg/controllers/local_node_controller_test.go b/pkg/controllers/local_node_controller_test.go index 67129db..a8b531d 100644 --- a/pkg/controllers/local_node_controller_test.go +++ b/pkg/controllers/local_node_controller_test.go @@ -71,10 +71,6 @@ var _ = Describe("test local node controller", func() { }, } - Eventually(func() error { - return createHarvesterNamespace(ctx, k8sClient) - }, "30s", "5s").ShouldNot(HaveOccurred()) - Eventually(func() error { return util.SetupLocalCluster(ctx, k8sClient) }, "30s", "5s").ShouldNot(HaveOccurred()) diff --git a/pkg/controllers/setup.go b/pkg/controllers/setup.go index ddce34b..e8c3dc6 100644 --- a/pkg/controllers/setup.go +++ b/pkg/controllers/setup.go @@ -6,10 +6,11 @@ import ( "time" "github.com/go-logr/logr" + "github.com/harvester/seeder/pkg/endpoint" "github.com/sirupsen/logrus" rufio "github.com/tinkerbell/rufio/api/v1alpha1" rufiocontrollers "github.com/tinkerbell/rufio/controller" - tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" "golang.org/x/sync/errgroup" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -18,20 +19,23 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/server" seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" "github.com/harvester/seeder/pkg/crd" "github.com/harvester/seeder/pkg/rufiojobwrapper" "github.com/harvester/seeder/pkg/util" "github.com/harvester/seeder/pkg/webhook" + ctrlruntimelog "sigs.k8s.io/controller-runtime/pkg/log" ) var ( - scheme = runtime.NewScheme() + scheme = runtime.NewScheme() + deploymentNamespace string //contains name of namespace where seeder is deployed ) const ( - defaultConnectionTimeout = 60 * time.Second + defaultRufioTimeout = 30 * time.Second ) type Server struct { @@ -56,9 +60,10 @@ func (s *Server) Start(ctx context.Context) error { utilruntime.Must(tinkv1alpha1.AddToScheme(scheme)) s.initLogs() mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: s.MetricsAddress, - Port: 9443, + Scheme: scheme, + Metrics: server.Options{ + BindAddress: ":9080", + }, HealthProbeBindAddress: s.ProbeAddress, LeaderElection: s.EnableLeaderElection, LeaderElectionID: "28b21117.harvesterhci.io", @@ -69,6 +74,9 @@ func (s *Server) Start(ctx context.Context) error { return err } + // used by other methods to lookup tink-stack and harvester-seeder-deployment services + deploymentNamespace = s.LeaderElectionNamespace + // create CRDs err = crd.Create(ctx, mgr.GetConfig()) if err != nil { @@ -96,15 +104,14 @@ func (s *Server) Start(ctx context.Context) error { rufiocontrollers.NewMachineReconciler( mgr.GetClient(), mgr.GetEventRecorderFor("machine-controller"), - rufiocontrollers.NewClientFunc(defaultConnectionTimeout), + rufiocontrollers.NewClientFunc(defaultRufioTimeout), ), rufiojobwrapper.NewRufioWrapper(ctx, mgr.GetClient(), - s.logger.WithName("controller").WithName("Job"), ), rufiocontrollers.NewTaskReconciler( mgr.GetClient(), - rufiocontrollers.NewClientFunc(defaultConnectionTimeout), + rufiocontrollers.NewClientFunc(defaultRufioTimeout), ), } @@ -121,6 +128,22 @@ func (s *Server) Start(ctx context.Context) error { Logger: s.logger.WithName("inventory-event-controller"), EventRecorder: mgr.GetEventRecorderFor("seeder"), }, + &WorkflowReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: s.logger.WithName("workflow-controller"), + EventRecorder: mgr.GetEventRecorderFor("seeder"), + }, + &ClusterTinkerbellTemplateReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: s.logger.WithName("cluster-tinkerbell-template-controller"), + }, + &ClusterTinkerbellWorkflowReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: s.logger.WithName("cluster-tinkerbell-workflow-controller"), + }, } var embedModeControllers = []controller{ @@ -180,9 +203,16 @@ func (s *Server) Start(ctx context.Context) error { return webhook.SetupWebhookServer(egCtx, mgr, s.LeaderElectionNamespace) }) + // create endpoint server + endpointServer := endpoint.NewServer(egCtx, mgr.GetClient(), s.logger.WithName("endpoint-server")) + eg.Go(func() error { + return endpointServer.Start() + }) + return eg.Wait() } func (s *Server) initLogs() { s.logger = zap.New(zap.UseDevMode(s.Debug)) + ctrlruntimelog.SetLogger(s.logger) } diff --git a/pkg/controllers/suite_test.go b/pkg/controllers/suite_test.go index 8c96ace..9f2d79d 100644 --- a/pkg/controllers/suite_test.go +++ b/pkg/controllers/suite_test.go @@ -28,16 +28,21 @@ import ( dockertest "github.com/ory/dockertest/v3" "github.com/ory/dockertest/v3/docker" rufio "github.com/tinkerbell/rufio/api/v1alpha1" - tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" - log "sigs.k8s.io/controller-runtime/pkg/log" + ctrlruntimelog "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/metrics/server" seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" "github.com/harvester/seeder/pkg/crd" + "github.com/harvester/seeder/pkg/endpoint" "github.com/harvester/seeder/pkg/mock" ) @@ -55,6 +60,7 @@ var ( k3sNodeAddress string k3sNodeGateway string redfishAddress string + watchedObjects []client.Object ) const ( @@ -71,6 +77,7 @@ func TestAPIs(t *testing.T) { if ok { suiteConfig.LabelFilter = "!skip-in-drone" } + suiteConfig.FailFast = true RunSpecs(t, "Controller Suite", suiteConfig, @@ -78,7 +85,7 @@ func TestAPIs(t *testing.T) { } var _ = BeforeSuite(func() { - log.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + ctrlruntimelog.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) ctx, cancel = context.WithCancel(context.TODO()) By("bootstrapping test environment") testEnv = &envtest.Environment{} @@ -107,53 +114,69 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) + deploymentNamespace = "harvester-system" + err = createHarvesterSystemNamespace(ctx, k8sClient) + Expect(err).NotTo(HaveOccurred()) + err = createTinkStackService(ctx, k8sClient) + Expect(err).NotTo(HaveOccurred()) + err = createSeederDeploymentService(ctx, k8sClient) + Expect(err).NotTo(HaveOccurred()) + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ - Scheme: scheme, - Port: 9444, - MetricsBindAddress: ":9080", - LeaderElection: false, + Scheme: scheme, + Metrics: server.Options{ + BindAddress: ":9080", + }, + LeaderElection: false, }) Expect(err).NotTo(HaveOccurred()) err = (&InventoryReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.inventory"), + Logger: ctrlruntimelog.Log.WithName("controller.inventory"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&mock.FakeBaseboardReconciller{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.baseboard"), + Logger: ctrlruntimelog.Log.WithName("controller.baseboard"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&mock.FakeBaseboardJobReconciller{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.bmcjob"), + Logger: ctrlruntimelog.Log.WithName("controller.bmcjob"), + }).SetupWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + + err = (&mock.FakeWorkflowReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: ctrlruntimelog.Log.WithName("controller.fake-workflow"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&AddressPoolReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.addresspool"), + Logger: ctrlruntimelog.Log.WithName("controller.addresspool"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&ClusterReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.cluster"), + Logger: ctrlruntimelog.Log.WithName("controller.cluster"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&InventoryEventReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.invenory-event"), + Logger: ctrlruntimelog.Log.WithName("controller.invenory-event"), EventRecorder: mgr.GetEventRecorderFor("seeder"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) @@ -161,18 +184,47 @@ var _ = BeforeSuite(func() { err = (&ClusterEventReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.cluster-event"), + Logger: ctrlruntimelog.Log.WithName("controller.cluster-event"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) err = (&LocalClusterReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), - Logger: log.Log.WithName("controller.local-cluster"), + Logger: ctrlruntimelog.Log.WithName("controller.local-cluster"), + EventRecorder: mgr.GetEventRecorderFor("seeder"), + }).SetupWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + + err = (&WorkflowReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: ctrlruntimelog.Log.WithName("controller.workflow"), EventRecorder: mgr.GetEventRecorderFor("seeder"), }).SetupWithManager(mgr) Expect(err).NotTo(HaveOccurred()) + err = (&ClusterTinkerbellTemplateReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: ctrlruntimelog.Log.WithName("controller.cluster-tinkerbell-template"), + }).SetupWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + + err = (&ClusterTinkerbellWorkflowReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Logger: ctrlruntimelog.Log.WithName("controller.cluster-tinkerbell-workflow"), + }).SetupWithManager(mgr) + Expect(err).NotTo(HaveOccurred()) + + endpointServer := endpoint.NewServer(ctx, mgr.GetClient(), ctrlruntimelog.Log.WithName("endpoint-server")) + go func() { + defer GinkgoRecover() + err = endpointServer.Start() + Expect(err).NotTo(HaveOccurred()) + }() + go func() { defer GinkgoRecover() err := mgr.Start(ctx) @@ -239,11 +291,108 @@ var _ = BeforeSuite(func() { var _ = AfterSuite(func() { By("tearing down the test environment") + err := cleanupObjects(ctx, k8sClient) + Expect(err).ToNot(HaveOccurred()) cancel() - err := pool.Purge(redfishMock) + err = pool.Purge(redfishMock) Expect(err).NotTo(HaveOccurred()) err = pool.Purge(k3sMock) Expect(err).NotTo(HaveOccurred()) err = testEnv.Stop() Expect(err).NotTo(HaveOccurred()) }) + +func createTinkStackService(ctx context.Context, k8sclient client.Client) error { + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: seederv1alpha1.DefaultTinkStackService, + Namespace: seederv1alpha1.DefaultLocalClusterNamespace, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Port: 8080, + }, + }, + }, + } + err := k8sclient.Create(ctx, svc) + if err != nil { + return err + } + + err = k8sclient.Get(ctx, types.NamespacedName{Name: svc.Name, Namespace: svc.Namespace}, svc) + if err != nil { + return err + } + + svc.Status = corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{{ + IP: "192.168.1.1", + }, + }, + }, + } + + watchedObjects = append(watchedObjects, svc) + return k8sclient.Status().Update(ctx, svc) +} + +func createSeederDeploymentService(ctx context.Context, k8sclient client.Client) error { + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: seederv1alpha1.DefaultSeederDeploymentService, + Namespace: seederv1alpha1.DefaultLocalClusterNamespace, + }, + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ + { + Port: 9090, + }, + }, + }, + } + err := k8sclient.Create(ctx, svc) + if err != nil { + return err + } + + err = k8sclient.Get(ctx, types.NamespacedName{Name: svc.Name, Namespace: svc.Namespace}, svc) + if err != nil { + return err + } + + svc.Status = corev1.ServiceStatus{ + LoadBalancer: corev1.LoadBalancerStatus{ + Ingress: []corev1.LoadBalancerIngress{{ + IP: "192.168.1.2", + }, + }, + }, + } + + watchedObjects = append(watchedObjects, svc) + return k8sclient.Status().Update(ctx, svc) +} + +func createHarvesterSystemNamespace(ctx context.Context, k8sclient client.Client) error { + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: seederv1alpha1.DefaultLocalClusterNamespace, + }, + } + + watchedObjects = append(watchedObjects, ns) + return k8sclient.Create(ctx, ns) +} + +func cleanupObjects(ctx context.Context, k8sclient client.Client) error { + for i := range watchedObjects { + index := i + 1 + if err := k8sclient.Delete(ctx, watchedObjects[len(watchedObjects)-index]); err != nil { + return err + } + } + return nil +} diff --git a/pkg/controllers/testdata/config.yaml b/pkg/controllers/testdata/config.yaml new file mode 100644 index 0000000..99f69f8 --- /dev/null +++ b/pkg/controllers/testdata/config.yaml @@ -0,0 +1,27 @@ +scheme_version: 1 +token: token # Replace with a desired token +os: + hostname: node1 # Set a hostname. This can be omitted if DHCP server offers hostnames. + ssh_authorized_keys: + - ssh-rsa ... # Replace with your public key + password: p@ssword # Replace with a your password + ntp_servers: + - 0.suse.pool.ntp.org + - 1.suse.pool.ntp.org +install: + mode: create + management_interface: + interfaces: + - name: ens5 + default_route: true + method: dhcp + bond_options: + mode: balance-tlb + miimon: 100 + device: /dev/sda # The target disk to install + iso_url: https://releases.rancher.com/harvester/master/harvester-master-amd64.iso + # tty: ttyS1,115200n8 # For machines without a VGA console + + vip: 10.10.0.19 + vip_mode: dhcp # Or static + vip_hw_addr: 52:54:00:ec:0e:0b # Leave empty when vip_mode is static \ No newline at end of file diff --git a/pkg/controllers/workflow_controller.go b/pkg/controllers/workflow_controller.go new file mode 100644 index 0000000..2a58aaf --- /dev/null +++ b/pkg/controllers/workflow_controller.go @@ -0,0 +1,114 @@ +package controllers + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +// WorkflowReconciler reconciles a Workflow object +type WorkflowReconciler struct { + client.Client + Scheme *runtime.Scheme + logr.Logger + record.EventRecorder +} + +/* Aim of workflow controller is to watch the workflow objects and disable ipxe/workflow options on hardware +object. This is needed as the default workflow reboots harvester post install, and this change is needed to ensure +that the inventory object is not stuck in an installation loop*/ + +func (r *WorkflowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + r.Info("reconcilling workflow object", req.Name, req.Namespace) + wObj := &tinkv1alpha1.Workflow{} + err := r.Get(ctx, req.NamespacedName, wObj) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + r.Error(err, "unable to fetch workflow object") + return ctrl.Result{}, err + } + + if wObj.DeletionTimestamp != nil { + // no further action is needed if workflow is being deleted + return ctrl.Result{}, nil + } + + r.Info(fmt.Sprintf("current workflow status: %v", wObj.Status), req.Name, req.Namespace) + + hw := &tinkv1alpha1.Hardware{} + err = r.Get(ctx, req.NamespacedName, hw) + if err != nil { + // for now we return error and requeue workflow + // this includes case when hardware object no longer exists + // may need to fine tune to handle hardware deletion + return ctrl.Result{}, err + } + + // enable/disable IPXE/Workflow based on workflow status + if wObj.Status.State == tinkv1alpha1.WorkflowStateSuccess && (*hw.Spec.Interfaces[0].Netboot.AllowWorkflow || *hw.Spec.Interfaces[0].Netboot.AllowPXE) { + + hw.Spec.Interfaces[0].Netboot.AllowWorkflow = &[]bool{false}[0] + hw.Spec.Interfaces[0].Netboot.AllowPXE = &[]bool{false}[0] + + return ctrl.Result{}, r.Update(ctx, hw) + } + + cluster, err := r.getOwnerCluster(ctx, wObj) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + return ctrl.Result{}, fmt.Errorf("error fetching parent cluster object for workflow %s: %v", wObj.Name, err) + } + + if cluster == nil { + return ctrl.Result{}, nil + } + + if wObj.Status.State == tinkv1alpha1.WorkflowStateSuccess { + r.EventRecorder.Event(cluster, "Normal", seederv1alpha1.WorkflowLoggerName, fmt.Sprintf("workflow %s completed successfully", wObj.Name)) + } + if wObj.Status.State == tinkv1alpha1.WorkflowStateFailed { + for _, task := range wObj.Status.Tasks { + for _, action := range task.Actions { + if action.Status == tinkv1alpha1.WorkflowStateFailed { + r.EventRecorder.Event(cluster, "Warning", seederv1alpha1.WorkflowLoggerName, fmt.Sprintf("workflow %s failed for task %s, action %s", wObj.Name, task.Name, action.Name)) + } + } + } + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *WorkflowReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&tinkv1alpha1.Workflow{}). + Complete(r) +} + +func (r *WorkflowReconciler) getOwnerCluster(ctx context.Context, wf *tinkv1alpha1.Workflow) (*seederv1alpha1.Cluster, error) { + owners := wf.GetOwnerReferences() + clusterObj := &seederv1alpha1.Cluster{} + for _, v := range owners { + r.Info("owners are", v.Name, wf.Namespace) + if v.Kind == "Cluster" { + err := r.Get(ctx, types.NamespacedName{Name: v.Name, Namespace: wf.Namespace}, clusterObj) + return clusterObj, err + } + } + return nil, nil +} diff --git a/pkg/controllers/workflow_controller_test.go b/pkg/controllers/workflow_controller_test.go new file mode 100644 index 0000000..7a61315 --- /dev/null +++ b/pkg/controllers/workflow_controller_test.go @@ -0,0 +1,355 @@ +package controllers + +import ( + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + rufio "github.com/tinkerbell/rufio/api/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + v1 "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" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +var _ = Describe("Successful workflow and hardware reconcile", func() { + var i *seederv1alpha1.Inventory + var c *seederv1alpha1.Cluster + var a *seederv1alpha1.AddressPool + var creds *v1.Secret + BeforeEach(func() { + a = &seederv1alpha1.AddressPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + Spec: seederv1alpha1.AddressSpec{ + CIDR: "192.168.1.1/29", + Gateway: "192.168.1.7", + }, + } + + i = &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + Spec: seederv1alpha1.InventorySpec{ + PrimaryDisk: "/dev/sda", + ManagementInterfaceMacAddress: "xx:xx:xx:xx:xx", + BaseboardManagementSpec: rufio.MachineSpec{ + Connection: rufio.Connection{ + Host: "localhost", + Port: 623, + InsecureTLS: true, + AuthSecretRef: v1.SecretReference{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + }, + }, + }, + } + + creds = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + StringData: map[string]string{ + "username": "admin", + "password": "password", + }, + } + + c = &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + Spec: seederv1alpha1.ClusterSpec{ + HarvesterVersion: "harvester_1_0_2", + Nodes: []seederv1alpha1.NodeConfig{ + { + InventoryReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + }, + }, + VIPConfig: seederv1alpha1.VIPConfig{ + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-test", + Namespace: "default", + }, + }, + ClusterConfig: seederv1alpha1.ClusterConfig{ + SSHKeys: []string{ + "abc", + "def", + }, + ConfigURL: "file:///testdata/config.yaml", + }, + }, + } + + Eventually(func() error { + return k8sClient.Create(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("reconcile hardware workflow in cluster controller reconcile", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted, current status is %s", tmpCluster.Status.Status) + } + + hwObj := &tinkv1alpha1.Hardware{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: i.Name, Namespace: i.Namespace}, hwObj); err != nil { + return err + } + + if *hwObj.Spec.Interfaces[0].Netboot.AllowPXE || *hwObj.Spec.Interfaces[0].Netboot.AllowWorkflow { + return fmt.Errorf("waiting for AllowPXE and AllowWorkflow to be set to false, current status %v %v", *hwObj.Spec.Interfaces[0].Netboot.AllowPXE, *hwObj.Spec.Interfaces[0].Netboot.AllowWorkflow) + } + + return nil + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + + Eventually(func() error { + // check and delete cluster if needed. Need this since one of the tests simulates removing cluster + // and checking gc of hardware objects + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + return k8sClient.Delete(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + Eventually(func() error { + return k8sClient.Delete(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + return fmt.Errorf("waiting for cluster finalizers to finish") + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) +}) + +var _ = Describe("Failed workflow and hardware reconcile", func() { + var i *seederv1alpha1.Inventory + var c *seederv1alpha1.Cluster + var a *seederv1alpha1.AddressPool + var creds *v1.Secret + BeforeEach(func() { + a = &seederv1alpha1.AddressPool{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + Spec: seederv1alpha1.AddressSpec{ + CIDR: "192.168.1.1/29", + Gateway: "192.168.1.7", + }, + } + + i = &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + Spec: seederv1alpha1.InventorySpec{ + PrimaryDisk: "/dev/sda", + ManagementInterfaceMacAddress: "xx:xx:xx:xx:xx", + BaseboardManagementSpec: rufio.MachineSpec{ + Connection: rufio.Connection{ + Host: "localhost", + Port: 623, + InsecureTLS: true, + AuthSecretRef: v1.SecretReference{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + }, + }, + }, + } + + creds = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + StringData: map[string]string{ + "username": "admin", + "password": "password", + }, + } + + c = &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + Spec: seederv1alpha1.ClusterSpec{ + HarvesterVersion: "harvester_1_0_2", + Nodes: []seederv1alpha1.NodeConfig{ + { + InventoryReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + }, + }, + VIPConfig: seederv1alpha1.VIPConfig{ + AddressPoolReference: seederv1alpha1.ObjectReference{ + Name: "workflow-cluster-fail-test", + Namespace: "default", + }, + }, + ClusterConfig: seederv1alpha1.ClusterConfig{ + SSHKeys: []string{ + "abc", + "def", + }, + ConfigURL: "file:///testdata/config.yaml", + }, + }, + } + + Eventually(func() error { + return k8sClient.Create(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Create(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + It("reconcile hardware workflow in cluster controller reconcile", func() { + Eventually(func() error { + tmpCluster := &seederv1alpha1.Cluster{} + if err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, tmpCluster); err != nil { + return err + } + + if tmpCluster.Status.Status != seederv1alpha1.ClusterTinkHardwareSubmitted { + return fmt.Errorf("expected status to be tink hardware submitted, current status is %s", tmpCluster.Status.Status) + } + + return nil + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Consistently(func() error { + hwObj := &tinkv1alpha1.Hardware{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: i.Name, Namespace: i.Namespace}, hwObj); err != nil { + return err + } + + if *hwObj.Spec.Interfaces[0].Netboot.AllowPXE && *hwObj.Spec.Interfaces[0].Netboot.AllowWorkflow { + return nil + } + return fmt.Errorf("expected AllowPXE and AllowWorkflow to be enabled, current status is %v %v", *hwObj.Spec.Interfaces[0].Netboot.AllowPXE, *hwObj.Spec.Interfaces[0].Netboot.AllowWorkflow) + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + + Eventually(func() error { + // check and delete cluster if needed. Need this since one of the tests simulates removing cluster + // and checking gc of hardware objects + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + return k8sClient.Delete(ctx, c) + }, "30s", "5s").ShouldNot(HaveOccurred()) + Eventually(func() error { + return k8sClient.Delete(ctx, i) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, creds) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + return k8sClient.Delete(ctx, a) + }, "30s", "5s").ShouldNot(HaveOccurred()) + + Eventually(func() error { + cObj := &seederv1alpha1.Cluster{} + err := k8sClient.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: c.Name}, cObj) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + return fmt.Errorf("waiting for cluster finalizers to finish") + }, "30s", "5s").ShouldNot(HaveOccurred()) + }) +}) diff --git a/pkg/endpoint/endpoint.go b/pkg/endpoint/endpoint.go new file mode 100644 index 0000000..d48b366 --- /dev/null +++ b/pkg/endpoint/endpoint.go @@ -0,0 +1,108 @@ +package endpoint + +import ( + "context" + "fmt" + "net/http" + "time" + + "github.com/go-logr/logr" + "github.com/gorilla/mux" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + "golang.org/x/sync/errgroup" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +type Server struct { + ctx context.Context + client client.Client + log logr.Logger + route *mux.Router +} + +func NewServer(ctx context.Context, client client.Client, log logr.Logger) *Server { + s := &Server{ + ctx: ctx, + client: client, + log: log, + } + r := mux.NewRouter() + r.HandleFunc("/disable/{namespace}/{name}", s.disableHardware).Methods("PUT") + r.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux) + s.route = r + return s +} + +func (s *Server) Start() error { + srv := &http.Server{ + Addr: fmt.Sprintf("0.0.0.0:%d", seederv1alpha1.DefaultEndpointPort), + WriteTimeout: 5 * time.Second, + ReadTimeout: 5 * time.Second, + IdleTimeout: 5 * time.Second, + Handler: s.route, + } + + eg, egctx := errgroup.WithContext(s.ctx) + eg.Go(func() error { + err := srv.ListenAndServe() + if err != http.ErrServerClosed { + return err + } + return nil + }) + + eg.Go(func() error { + <-egctx.Done() + return srv.Shutdown(egctx) + }) + + return eg.Wait() +} + +func (s *Server) disableHardware(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + name, ok := vars["name"] + if !ok { + w.WriteHeader(http.StatusInternalServerError) + s.log.Error(fmt.Errorf("error: no hw name specified"), "") + return + } + + namespace, ok := vars["namespace"] + if !ok { + w.WriteHeader(http.StatusInternalServerError) + s.log.Error(fmt.Errorf("error: no hw namespace specified"), "") + return + } + + hwObj := &tinkv1alpha1.Hardware{} + if err := s.client.Get(s.ctx, types.NamespacedName{Name: name, Namespace: namespace}, hwObj); err != nil { + if apierrors.IsNotFound(err) { + w.WriteHeader(http.StatusNotFound) + return + } + w.WriteHeader(http.StatusInternalServerError) + s.log.Error(err, "error looking up hw object", name, namespace) + return + } + + // disable Netboot AllowPXE on all interfaces in hwObj + for i, netifs := range hwObj.Spec.Interfaces { + if *netifs.Netboot.AllowPXE { + hwObj.Spec.Interfaces[i].Netboot.AllowPXE = &[]bool{false}[0] + + } + } + + if err := s.client.Update(s.ctx, hwObj); err != nil { + w.WriteHeader(http.StatusInternalServerError) + s.log.Error(err, "error disabling AllowPXE", hwObj.Name, hwObj.Namespace) + return + } + + w.WriteHeader(http.StatusAccepted) +} diff --git a/pkg/endpoint/endpoint_test.go b/pkg/endpoint/endpoint_test.go new file mode 100644 index 0000000..826ae3c --- /dev/null +++ b/pkg/endpoint/endpoint_test.go @@ -0,0 +1,153 @@ +package endpoint + +import ( + "context" + "fmt" + "net/http" + "os" + "testing" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" + "github.com/stretchr/testify/require" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/harvester/seeder/pkg/mock" +) + +var ( + hardwareObjects = ` +apiVersion: tinkerbell.org/v1alpha1 +kind: Hardware +metadata: + name: hp-151 + namespace: default +spec: + disks: + - device: /dev/sda + interfaces: + - dhcp: + arch: x86_64 + hostname: hp-151-seeder + ip: + address: 172.19.108.3 + gateway: 172.19.104.1 + netmask: 255.255.248.0 + lease_time: 86400 + mac: 5c:b9:01:88:d3:75 + uefi: true + netboot: + allowPXE: true + osie: + baseURL: http://172.19.96.23/iso/ + metadata: + facility: + facility_code: on_prem + instance: + operating_system: + distro: harvester + version: v1.2.0 +--- +apiVersion: tinkerbell.org/v1alpha1 +kind: Hardware +metadata: + name: hp-153 + namespace: default +spec: + disks: + - device: /dev/sda + interfaces: + - dhcp: + arch: x86_64 + hostname: hp-153-seeder + ip: + address: 172.19.108.4 + gateway: 172.19.104.1 + netmask: 255.255.248.0 + lease_time: 86400 + mac: 5c:b9:01:88:d3:75 + uefi: true + netboot: + allowPXE: true + osie: + baseURL: http://172.19.96.23/iso/ + metadata: + facility: + facility_code: on_prem + instance: + operating_system: + distro: harvester + version: v1.2.0 +` + fakeclient client.WithWatch +) + +func TestMain(t *testing.M) { + log := zap.New(zap.UseDevMode(true)) + ctx, cancel := context.WithCancel(context.TODO()) + objs, err := mock.GenerateObjectsFromVar(hardwareObjects) + if err != nil { + log.Error(err, "error generating hw objects") + os.Exit(1) + } + fakeclient, err = mock.GenerateFakeClientFromObjects(objs) + if err != nil { + log.Error(err, "error generating mock client") + os.Exit(1) + } + + s := NewServer(ctx, fakeclient, log) + go func() { + if err := s.Start(); err != nil { + log.Error(err, "error starting server") + os.Exit(1) + } + }() + + code := t.Run() + cancel() + os.Exit(code) +} + +func Test_disableHardware(t *testing.T) { + var tests = []struct { + name string + namespace string + httpStatusCode int + checkPXEDisabled bool + }{ + { + name: "hp-151", + namespace: "default", + httpStatusCode: 202, + checkPXEDisabled: true, + }, + { + name: "hp-154", + namespace: "default", + httpStatusCode: 404, + checkPXEDisabled: false, + }, + } + assert := require.New(t) + for _, t := range tests { + req, err := http.NewRequest("PUT", fmt.Sprintf("http://localhost:%d/disable/%s/%s", seederv1alpha1.DefaultEndpointPort, t.namespace, t.name), nil) + assert.NoError(err, fmt.Sprintf("expected no error during generation of request for test %s", t.name)) + resp, err := http.DefaultClient.Do(req) + assert.NoErrorf(err, fmt.Sprintf("error making call for test %s", t.name)) + assert.Equal(resp.StatusCode, t.httpStatusCode) + if t.checkPXEDisabled { + hwObj := &tinkv1alpha1.Hardware{} + err = fakeclient.Get(context.TODO(), types.NamespacedName{Name: t.name, Namespace: t.namespace}, hwObj) + assert.NoError(err, "expected no error looking up object") + var disabled bool + for _, v := range hwObj.Spec.Interfaces { + disabled = disabled || *v.Netboot.AllowPXE + } + assert.False(disabled) + } + } + +} diff --git a/pkg/mock/mock.go b/pkg/mock/mock.go index 6c0f843..6186041 100644 --- a/pkg/mock/mock.go +++ b/pkg/mock/mock.go @@ -5,6 +5,7 @@ import ( "github.com/rancher/wrangler/pkg/yaml" rufio "github.com/tinkerbell/rufio/api/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" @@ -69,6 +70,8 @@ metadata: ` ) +var statusSubResources = []client.Object{&seederv1alpha1.Cluster{}, &seederv1alpha1.Inventory{}, &seederv1alpha1.AddressPool{}, &seederv1alpha1.Cluster{}} + func generateObjects() ([]runtime.Object, error) { objs, err := GenerateObjectsFromVar(DefaultObjects) return objs, err @@ -94,6 +97,7 @@ func GenerateFakeClientFromObjects(objs []runtime.Object) (client.WithWatch, err utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(seederv1alpha1.AddToScheme(scheme)) utilruntime.Must(rufio.AddToScheme(scheme)) - c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(objs...).WithStatusSubresource(&seederv1alpha1.Cluster{}).Build() + utilruntime.Must(tinkv1alpha1.AddToScheme(scheme)) + c := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(objs...).WithStatusSubresource(statusSubResources...).Build() return c, nil } diff --git a/pkg/mock/workflow_controller.go b/pkg/mock/workflow_controller.go new file mode 100644 index 0000000..bd63c6d --- /dev/null +++ b/pkg/mock/workflow_controller.go @@ -0,0 +1,54 @@ +package mock + +import ( + "context" + "strings" + + "github.com/go-logr/logr" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// FakeWorkflowReconciler implements a fake reconcile loop for workflow integration testing +type FakeWorkflowReconciler struct { + client.Client + logr.Logger + Scheme *runtime.Scheme +} + +func (f *FakeWorkflowReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + w := &tinkv1alpha1.Workflow{} + f.Info("Reconcilling workflow job objects", req.Name, req.Namespace) + err := f.Get(ctx, req.NamespacedName, w) + if err != nil { + if apierrors.IsNotFound(err) { + return ctrl.Result{}, nil + } + f.Error(err, "error fetching baseboard object") + return ctrl.Result{}, err + } + + // state is already patched nothing else to do + if w.Status.State != "" { + return ctrl.Result{}, nil + } + + if strings.Contains(w.Name, "fail") { + w.Status.State = tinkv1alpha1.WorkflowStateFailed + } else { + w.Status.State = tinkv1alpha1.WorkflowStateSuccess + } + + return ctrl.Result{}, f.Status().Update(ctx, w) + +} + +// SetupWithManager sets up the controller with the Manager. +func (f *FakeWorkflowReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&tinkv1alpha1.Workflow{}). + Complete(f) +} diff --git a/pkg/rufiojobwrapper/wrapper.go b/pkg/rufiojobwrapper/wrapper.go index 361c75a..88b91e7 100644 --- a/pkg/rufiojobwrapper/wrapper.go +++ b/pkg/rufiojobwrapper/wrapper.go @@ -3,7 +3,6 @@ package rufiojobwrapper import ( "context" - "github.com/go-logr/logr" rufiocontrollers "github.com/tinkerbell/rufio/controller" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -18,7 +17,7 @@ type RufioJobWrapper struct { context.Context } -func NewRufioWrapper(ctx context.Context, client client.Client, logr logr.Logger) *RufioJobWrapper { +func NewRufioWrapper(ctx context.Context, client client.Client) *RufioJobWrapper { return &RufioJobWrapper{ rufiocontrollers.NewJobReconciler(client), ctx, diff --git a/pkg/tink/template.go b/pkg/tink/template.go new file mode 100644 index 0000000..0361690 --- /dev/null +++ b/pkg/tink/template.go @@ -0,0 +1,86 @@ +package tink + +import ( + "fmt" + + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + "gopkg.in/yaml.v3" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" +) + +const ( + HegelDefaultPort = "50061" + // override images can be defined in the tink-images configmap in seeder naemspace, and will override images in the default workflow + StreamHarvesterImageKey = "steam-harvester-image" + ConfigureHarvesterImageKey = "configure-harvester-image" + RebootHarvesterImageKey = "reboot-harvester-image" +) + +func GenerateTemplate(hegelEndpoint string, cm *corev1.ConfigMap, i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) (*tinkv1alpha1.Template, error) { + template := &tinkv1alpha1.Template{ + ObjectMeta: metav1.ObjectMeta{ + Name: i.Name, + Namespace: i.Namespace, + }, + } + + data, err := generateDataTemplate(hegelEndpoint, cm, i, c) + if err != nil { + return nil, fmt.Errorf("error generating template data: %v", err) + } + + template.Spec.Data = data + return template, nil +} + +func generateDataTemplate(hegelEndpoint string, cm *corev1.ConfigMap, i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) (*string, error) { + //set StreamHarvester action environment variables + DefaultStreamHarvesterAction.Environment[DestDisk] = i.Spec.PrimaryDisk + DefaultStreamHarvesterAction.Environment[ImageURL] = fmt.Sprintf("%s/%s/harvester-%s-%s.raw.gz", c.Spec.ImageURL, c.Spec.HarvesterVersion, c.Spec.HarvesterVersion, i.Spec.Arch) + + //set ConfigureHarvester action environment variables + DefaultConfigureHarvesterAction.Environment[HarvesterDevice] = i.Spec.PrimaryDisk + DefaultConfigureHarvesterAction.Environment[HarvesterCloudInitURL] = fmt.Sprintf("http://%s:%s/2009-04-04/user-data", + hegelEndpoint, HegelDefaultPort) + + //svc.Status.LoadBalancer.Ingress[0].IP + + // override images if specified + if cm != nil { + if val, ok := cm.Data[StreamHarvesterImageKey]; ok && val != "" { + DefaultStreamHarvesterAction.Image = val + } + + if val, ok := cm.Data[ConfigureHarvesterImageKey]; ok && val != "" { + DefaultConfigureHarvesterAction.Image = val + } + + if val, ok := cm.Data[RebootHarvesterImageKey]; ok && val != "" { + DefaultRebootNodeAction.Image = val + } + + } + + // Define action sequence + DefaultInstallationTask.Actions = []Action{ + DefaultStreamHarvesterAction, + DefaultConfigureHarvesterAction, + DefaultRebootNodeAction, + } + + // Define workflow + DefaultHarvesterInstallationWorkflow.Tasks = []Task{ + DefaultInstallationTask, + } + + output, err := yaml.Marshal(&DefaultHarvesterInstallationWorkflow) + if err != nil { + return nil, err + } + + data := string(output) + return &data, nil +} diff --git a/pkg/tink/template_test.go b/pkg/tink/template_test.go new file mode 100644 index 0000000..6bee4fc --- /dev/null +++ b/pkg/tink/template_test.go @@ -0,0 +1,46 @@ +package tink + +import ( + "testing" + + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" + "github.com/rancher/wrangler/pkg/yaml" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func Test_GenerateTemplate(t *testing.T) { + assert := require.New(t) + i := &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-inventory", + Namespace: "harvester-system", + }, + Spec: seederv1alpha1.InventorySpec{ + PrimaryDisk: "/dev/sda", + }, + } + + c := &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "harvester-system", + }, + Spec: seederv1alpha1.ClusterSpec{ + HarvesterVersion: "v1.2.0", + ImageURL: "http://imagestore/", + }, + } + + template, err := GenerateTemplate("192.168.1.100", nil, i, c) + assert.NoError(err, "exppected no error during template generation") + assert.Equal(template.Name, i.Name, "expected template name to match inventory name") + assert.Equal(template.Namespace, i.Namespace, "expected template namespace to match inventory namespace") + assert.NotNil(template.Spec.Data, "expected .spec.data to not be nil") + workflowObj := &Workflow{} + err = yaml.Unmarshal([]byte(*template.Spec.Data), workflowObj) + assert.NoError(err, "expected no error while unmarshalling template.spec.data") + assert.Len(workflowObj.Tasks, 1, "expected to find 1 task") + assert.Len(workflowObj.Tasks[0].Actions, 3, "expected to find 3 actions to be performed by the template") + +} diff --git a/pkg/tink/testdata/create.yaml b/pkg/tink/testdata/create.yaml new file mode 100644 index 0000000..99f69f8 --- /dev/null +++ b/pkg/tink/testdata/create.yaml @@ -0,0 +1,27 @@ +scheme_version: 1 +token: token # Replace with a desired token +os: + hostname: node1 # Set a hostname. This can be omitted if DHCP server offers hostnames. + ssh_authorized_keys: + - ssh-rsa ... # Replace with your public key + password: p@ssword # Replace with a your password + ntp_servers: + - 0.suse.pool.ntp.org + - 1.suse.pool.ntp.org +install: + mode: create + management_interface: + interfaces: + - name: ens5 + default_route: true + method: dhcp + bond_options: + mode: balance-tlb + miimon: 100 + device: /dev/sda # The target disk to install + iso_url: https://releases.rancher.com/harvester/master/harvester-master-amd64.iso + # tty: ttyS1,115200n8 # For machines without a VGA console + + vip: 10.10.0.19 + vip_mode: dhcp # Or static + vip_hw_addr: 52:54:00:ec:0e:0b # Leave empty when vip_mode is static \ No newline at end of file diff --git a/pkg/tink/tink.go b/pkg/tink/tink.go index f26975b..8ed6fea 100644 --- a/pkg/tink/tink.go +++ b/pkg/tink/tink.go @@ -3,12 +3,15 @@ package tink import ( "bytes" "fmt" - "html/template" - "strings" + "io" + "net/http" + "text/template" - "github.com/pkg/errors" - tinkv1alpha1 "github.com/tinkerbell/tink/pkg/apis/core/v1alpha1" + "github.com/harvester/harvester-installer/pkg/config" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" "github.com/harvester/seeder/pkg/util" @@ -16,14 +19,15 @@ import ( const ( defaultLeaseTime = 86400 - defaultArch = "x86_64" defaultFacilityCode = "on_prem" defaultDistro = "harvester" defaultISOURL = "https://releases.rancher.com/harvester/" + defaultEvent = "SUCCEEDED" + defaultMethod = "PUT" ) // GenerateHWRequest will generate the tinkerbell Hardware type object -func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) (hw *tinkv1alpha1.Hardware, err error) { +func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster, seederDeploymentService *corev1.Service, tinkStackService *corev1.Service) (hw *tinkv1alpha1.Hardware, err error) { // generate metadata mode := "join" @@ -31,16 +35,27 @@ func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) ( mode = "create" } - var m string - if strings.Contains(c.Spec.HarvesterVersion, "v1.0") { - m, err = generateMetaDataV10(c.Spec.ConfigURL, c.Spec.HarvesterVersion, i.Spec.ManagementInterfaceMacAddress, mode, - i.Spec.PrimaryDisk, c.Status.ClusterAddress, c.Status.ClusterToken, i.Status.GeneratedPassword, c.Spec.ImageURL, c.Spec.ClusterConfig.Nameservers, c.Spec.ClusterConfig.SSHKeys) - } else { - m, err = generateMetaDataV11(c.Spec.ConfigURL, c.Spec.HarvesterVersion, i.Spec.ManagementInterfaceMacAddress, mode, - i.Spec.PrimaryDisk, c.Status.ClusterAddress, c.Status.ClusterToken, i.Status.GeneratedPassword, c.Spec.ImageURL, c.Spec.ClusterConfig.Nameservers, c.Spec.ClusterConfig.SSHKeys) + if len(seederDeploymentService.Status.LoadBalancer.Ingress) == 0 { + return nil, fmt.Errorf("waiting for ingress to be populated on svc: %s", seederDeploymentService.Name) + } + bondOptions := make(map[string]string) + if c.Spec.BondOptions == nil { + bondOptions["mode"] = "balance-tlb" + bondOptions["miimon"] = "100" } + userdata, err := generateCloudConfig(c.Spec.ConfigURL, i.Spec.ManagementInterfaceMacAddress, mode, c.Status.ClusterAddress, + c.Status.ClusterToken, i.Status.GeneratedPassword, i.Status.Address, i.Status.Netmask, i.Status.Gateway, c.Spec.ClusterConfig.Nameservers, c.Spec.ClusterConfig.SSHKeys, bondOptions, c.Spec.ImageURL, c.Spec.HarvesterVersion, seederDeploymentService.Status.LoadBalancer.Ingress[0].IP, i.Name, i.Namespace, c.Spec.StreamImageMode, c.Spec.WipeDisks, c.Spec.VlanID, i.Spec.Arch, i.Spec.PrimaryDisk, fmt.Sprintf("%s-%s", i.Name, i.Namespace)) + if err != nil { - return nil, errors.Wrap(err, "error during metadata generation") + return nil, fmt.Errorf("error during HW generation: %v", err) + } + + // work around needed since boots represents amd64 arch as x86_64 + var hwArch string + if i.Spec.Arch == "amd64" { + hwArch = "x86_64" + } else { + hwArch = "aarch64" } hw = &tinkv1alpha1.Hardware{ @@ -49,19 +64,18 @@ func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) ( Namespace: i.Namespace, }, Spec: tinkv1alpha1.HardwareSpec{ + UserData: &userdata, Interfaces: []tinkv1alpha1.Interface{ { Netboot: &tinkv1alpha1.Netboot{ - AllowPXE: &[]bool{true}[0], - OSIE: &tinkv1alpha1.OSIE{ - BaseURL: c.Spec.ImageURL, - }, + AllowPXE: &[]bool{true}[0], + AllowWorkflow: &[]bool{true}[0], }, DHCP: &tinkv1alpha1.DHCP{ MAC: i.Spec.ManagementInterfaceMacAddress, Hostname: fmt.Sprintf("%s-%s", i.Name, i.Namespace), LeaseTime: defaultLeaseTime, - Arch: defaultArch, + Arch: hwArch, UEFI: true, IP: &tinkv1alpha1.IP{ Address: i.Status.Address, @@ -81,7 +95,6 @@ func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) ( FacilityCode: defaultFacilityCode, }, Instance: &tinkv1alpha1.MetadataInstance{ - Userdata: m, OperatingSystem: &tinkv1alpha1.MetadataInstanceOperatingSystem{ Version: c.Spec.HarvesterVersion, Distro: defaultDistro, @@ -91,96 +104,177 @@ func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) ( }, } + // if not using StreamImage mode then define a custom ipxe url with info needed to provision harvester + if !c.Spec.StreamImageMode { + customIPXEScript, err := generateIPXEScript(c.Spec.HarvesterVersion, c.Spec.ImageURL, fmt.Sprintf("http://%s:%s/2009-04-04/user-data", + tinkStackService.Status.LoadBalancer.Ingress[0].IP, HegelDefaultPort), i.Spec.ManagementInterfaceMacAddress, i.Spec.Arch) + if err != nil { + return nil, fmt.Errorf("error generating custom ipxe script for inventory %s: %v", i.Name, err) + } + for i := range hw.Spec.Interfaces { + hw.Spec.Interfaces[i].Netboot.IPXE = &tinkv1alpha1.IPXE{ + Contents: customIPXEScript, + } + } + } return hw, nil } -// generateMetaDataV10 is a wrapper to generate metadata for nodes to create or join a cluster -func generateMetaDataV10(configURL, version, hwAddress, mode, disk, vip, token, password, imageurl string, Nameservers, SSHKeys []string) (metadata string, err error) { - - var tmpStruct struct { - ConfigURL string - HWAddress string - Mode string - Disk string - VIP string - Token string - SSHKeys []string - Nameservers []string - Password string - IsoURL string - } - var output bytes.Buffer - tmpStruct.ConfigURL = configURL - tmpStruct.HWAddress = hwAddress - tmpStruct.Mode = mode - tmpStruct.Disk = disk - tmpStruct.VIP = vip - tmpStruct.Token = token - tmpStruct.Password = password - tmpStruct.SSHKeys = SSHKeys - tmpStruct.Nameservers = Nameservers - tmpStruct.Password = password - endpoint := defaultISOURL - if imageurl != "" { - endpoint = imageurl +// GenerateWorkflow binds the template associated with inventory to the workflow +// this needs to be done before the ipxe boot is performed to ensure correct workflow is executed on reboot +func GenerateWorkflow(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster) (workflow *tinkv1alpha1.Workflow) { + workflow = &tinkv1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: i.Name, + Namespace: i.Namespace, + }, + Spec: tinkv1alpha1.WorkflowSpec{ + TemplateRef: i.Name, + HardwareRef: i.Name, + HardwareMap: map[string]string{ + "device_1": i.Spec.ManagementInterfaceMacAddress, + }, + }, } - tmpStruct.IsoURL = fmt.Sprintf("%s/%s/harvester-%s-amd64.iso", endpoint, version, version) - - var metaDataStruct = `{{ if ne .ConfigURL ""}}harvester.install.config_url={{ .ConfigURL }}{{end}} harvester.install.networks.harvester-mgmt.interfaces="hwAddr:{{ .HWAddress }}" ip=dhcp harvester.install.networks.harvester-mgmt.method=dhcp harvester.install.networks.harvester-mgmt.bond_options.mode=balance-tlb harvester.install.networks.harvester-mgmt.bond_options.miimon=100 console=ttyS1,115200 harvester.install.mode={{ .Mode }} harvester.token={{ .Token }} harvester.os.password={{ .Password }} {{ range $v := .SSHKeys}}harvester.os.ssh_authorized_keys=\"- {{ $v }} \ "{{ end }}{{range $v := .Nameservers}}harvester.os.dns_nameservers={{ $v }} {{end}} harvester.install.vip={{ .VIP }} harvester.install.vip_mode=static harvester.install.iso_url={{ .IsoURL }} harvester.install.device={{ .Disk }} {{if eq .Mode "join"}}harvester.server_url={{ printf "https://%s:8443" .VIP }}{{end}}` - metadataTmpl := template.Must(template.New("MetaData").Parse(metaDataStruct)) + if c.Spec.ClusterConfig.CustomProvisioningTemplate != "" { + workflow.Spec.TemplateRef = c.Spec.ClusterConfig.CustomProvisioningTemplate + } - err = metadataTmpl.Execute(&output, tmpStruct) + return workflow +} +func generateCloudConfig(configURL, hwAddress, mode, vip, token, password, ip, subnetMask, gateway string, Nameservers, SSHKeys []string, bondOptions map[string]string, imageURL string, harvesterVersion string, webhookURL string, hwName string, hwNamespace string, streamImage bool, wipeDisks bool, vlanID int, arch string, disk string, hostname string) (string, error) { + hc := config.NewHarvesterConfig() + if configURL != "" { + if err := readConfigURL(hc, configURL); err != nil { + return "", err + } + } + hc.SchemeVersion = 1 + hc.Token = token + if mode == "join" { + hc.ServerURL = fmt.Sprintf("https://%s:443", vip) + } else { + hc.Install.Vip = vip + hc.Install.VipMode = "static" + } + hc.Install.Mode = mode + hc.Install.ManagementInterface = config.Network{ + Method: "static", + IP: ip, + SubnetMask: subnetMask, + Gateway: gateway, + DefaultRoute: true, + Interfaces: []config.NetworkInterface{ + { + HwAddr: hwAddress, + }, + }, + } + if vlanID > 0 { + hc.Install.ManagementInterface.VlanID = vlanID + } + hc.Install.Automatic = true + hc.OS.Password = password + hc.OS.DNSNameservers = append(hc.OS.DNSNameservers, Nameservers...) + hc.OS.SSHAuthorizedKeys = append(hc.OS.SSHAuthorizedKeys, SSHKeys...) + hc.OS.Hostname = hostname + hc.Install.ManagementInterface.BondOptions = bondOptions + hc.Install.WipeDisks = wipeDisks + hc.Install.Device = disk + hc.Install.SkipChecks = true + // for versions older than v1.2.x where streaming image mode is not available + // we need to provide ISO URL + if !streamImage { + //hc.Install.ConfigURL = "" // reset the config url + hc.Install.ISOURL = fmt.Sprintf("%s/%s/harvester-%s-%s.iso", imageURL, harvesterVersion, harvesterVersion, arch) + hc.Install.Webhooks = []config.Webhook{ + { + Event: defaultEvent, + Method: defaultMethod, + URL: fmt.Sprintf("http://%s:%d/disable/%s/%s", webhookURL, seederv1alpha1.DefaultEndpointPort, hwNamespace, hwName), + }, + } + } + hcBytes, err := yaml.Marshal(hc) if err != nil { - return metadata, err + return "", fmt.Errorf("error marshalling yaml: %v", err) } - - metadata = output.String() - return metadata, nil + return string(hcBytes), nil } -func generateMetaDataV11(configURL, version, hwAddress, mode, disk, vip, token, password, imageurl string, Nameservers, SSHKeys []string) (metadata string, err error) { +// generateIPXEScript will generate an inline ipxe script similar to https://github.com/harvester/ipxe-examples/blob/main/general/ipxe-create +// and uses the same for create / join of node +func generateIPXEScript(harvesterVersion, isoURL, hegelEndpoint, macAddress, arch string) (string, error) { - var tmpStruct struct { - ConfigURL string - HWAddress string - Mode string - Disk string - VIP string - Token string - SSHKeys []string - Nameservers []string - Password string - IsoURL string + ipxeTemplateStruct := struct { + Version string + ISOURL string + HegelEndpoint string + MacAddress string + Arch string + }{ + Version: harvesterVersion, + ISOURL: isoURL, + HegelEndpoint: hegelEndpoint, + MacAddress: macAddress, + Arch: arch, } - var output bytes.Buffer - tmpStruct.ConfigURL = configURL - tmpStruct.HWAddress = hwAddress - tmpStruct.Mode = mode - tmpStruct.Disk = disk - tmpStruct.VIP = vip - tmpStruct.Token = token - tmpStruct.Password = password - tmpStruct.SSHKeys = SSHKeys - tmpStruct.Nameservers = Nameservers - tmpStruct.Password = password - endpoint := defaultISOURL - if imageurl != "" { - endpoint = imageurl - } - tmpStruct.IsoURL = fmt.Sprintf("%s/%s/harvester-%s-amd64.iso", endpoint, version, version) - var metaDataStruct = `{{ if ne .ConfigURL ""}}harvester.install.config_url={{ .ConfigURL }}{{end}} harvester.install.management_interface.interfaces="hwAddr:{{ .HWAddress }}" ip=dhcp harvester.install.management_interface.method=dhcp harvester.management_interface.bond_options.mode=balance-tlb harvester.install.management_interface.bond_options.miimon=100 console=ttyS1,115200 harvester.install.mode={{ .Mode }} harvester.token={{ .Token }} harvester.os.password={{ .Password }} {{ range $v := .SSHKeys}}harvester.os.ssh_authorized_keys=\"- {{ $v }} \ "{{ end }}{{range $v := .Nameservers}}harvester.os.dns_nameservers={{ $v }} {{end}} harvester.install.vip={{ .VIP }} harvester.install.vip_mode=static harvester.install.iso_url={{ .IsoURL }} harvester.install.device={{ .Disk }} {{if eq .Mode "join"}}harvester.server_url={{ printf "https://%s:443" .VIP }}{{end}} harvester.scheme_version=1` + var output bytes.Buffer - metadataTmpl := template.Must(template.New("MetaData").Parse(metaDataStruct)) + ipxeTemplate := `#!ipxe +set version {{ .Version }} +set base {{ .ISOURL}}/{{ .Version }} +set arch {{ .Arch }} +dhcp +iflinkwait -t 5000 +goto ${ifname} +:net0 +set address ${net0/mac} +goto setupboot +:net1 +set address ${net1/mac} +goto setupboot +:net2 +set address ${net2/mac} +goto setupboot +:net3 +set address ${net3/mac} +goto setupboot - err = metadataTmpl.Execute(&output, tmpStruct) +:setupboot +kernel ${base}/harvester-${version}-vmlinuz-${arch} initrd=harvester-${version}-initrd-${arch} ip=dhcp net.ifnames=1 rd.cos.disable rd.noverifyssl BOOTIF={{ .MacAddress }} root=live:${base}/harvester-${version}-rootfs-${arch}.squashfs console=tty1 harvester.install.automatic=true boot_cmd='echo include_ping_test=yes >> /etc/conf.d/net-online' harvester.install.config_url={{ .HegelEndpoint }} +initrd ${base}/harvester-${version}-initrd-${arch} +boot +` + ipxeTmpl := template.Must(template.New("IPXE").Parse(ipxeTemplate)) + err := ipxeTmpl.Execute(&output, ipxeTemplateStruct) + if err != nil { + return "", fmt.Errorf("error generating ipxe template: %v", err) + } + return output.String(), nil +} +func readConfigURL(hc *config.HarvesterConfig, url string) error { + // FileTransport is needed to make it easier to run unit tests + t := &http.Transport{} + t.RegisterProtocol("file", http.NewFileTransport(http.Dir("."))) + c := &http.Client{Transport: t} + resp, err := c.Get(url) if err != nil { - return metadata, err + return fmt.Errorf("error fetching config url %s: %v", url, err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("error during http call, status code: %v", resp.Status) } - metadata = output.String() - return metadata, nil + content, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("error reading url response body: %v", err) + } + err = yaml.Unmarshal(content, hc) + return err } diff --git a/pkg/tink/tink_test.go b/pkg/tink/tink_test.go index 935f56f..4bf5419 100644 --- a/pkg/tink/tink_test.go +++ b/pkg/tink/tink_test.go @@ -1,10 +1,14 @@ package tink import ( + "fmt" "testing" + "github.com/harvester/harvester-installer/pkg/config" + "github.com/rancher/wrangler/pkg/yaml" "github.com/stretchr/testify/require" rufio "github.com/tinkerbell/rufio/api/v1alpha1" + tinkv1alpha1 "github.com/tinkerbell/tink/api/v1alpha1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -12,24 +16,48 @@ import ( "github.com/harvester/seeder/pkg/util" ) -func Test_generateMetaDataV10(t *testing.T) { +func Test_createModeCloudConfig(t *testing.T) { assert := require.New(t) - m, err := generateMetaDataV10("http://localhost", "v1.0.1", "xx:xx:xx:xx:xx", "create", - "/dev/sda", "192.168.1.100", "token", "password", "v1.0.2", []string{"8.8.8.8"}, []string{"abc"}) - assert.NoError(err, "no error should have occured") - assert.Contains(m, "harvester.install.mode=create", "expected to find create mode in metadata") - assert.Contains(m, "hwAddr:xx:xx:xx:xx:xx", "expected to find mac address in metadata") - assert.NotContains(m, "scheme_version", "expected to not find scheme_version") + cloudConfig, err := generateCloudConfig("file:///testdata/create.yaml", "ab:cd:ef:gh:ij:kl", "create", "192.168.1.100", "token", "password", "192.168.1.101", "255.255.255.0", "192.168.1.1", []string{"8.8.8.8"}, []string{"ssh-key 1", "ssh-key 2"}, nil, "http://imagestore/iso", "v1.2.1", "http://seeder-endpoint", "sample", "harvester-system", false, true, 1, "amd64", "/dev/vda", "test") + assert.NoError(err) + hc := config.NewHarvesterConfig() + err = yaml.Unmarshal([]byte(cloudConfig), hc) + assert.NoError(err) + assert.True(hc.Install.Automatic, "expected automatic installation to be set") + assert.Empty(hc.ServerURL, "expected serverURL to be empty") + assert.NotEmpty(hc.Install.Vip, "expected VIP to be set") + assert.Equal(hc.Install.VipMode, "static", "expected vip mode to be static") + assert.Equal(hc.Install.Mode, "create", "expected install mode to be create") + assert.Len(hc.Install.ManagementInterface.Interfaces, 1, "expected to find 1 interface defined") + assert.Empty(hc.Install.ConfigURL, "expected configURL to be set") + assert.NotEmpty(hc.OS.Password, "expected password to be set") + assert.Len(hc.OS.DNSNameservers, 1, "expected to find 1 dns server") + assert.Len(hc.OS.SSHAuthorizedKeys, 2, "expected to find 2 ssh keys specified") + assert.NotEmpty(hc.Install.ManagementInterface.IP, "expected IP to be set") + assert.NotEmpty(hc.Install.ManagementInterface.Gateway, "expected gateway to be set") + assert.NotEmpty(hc.Install.ManagementInterface.SubnetMask, "expected subnet mask to be set") + assert.True(hc.Install.WipeDisks, "expected wipe disks to be set") } -func Test_generateMetaDataV11(t *testing.T) { +func Test_joinModeCloudConfig(t *testing.T) { assert := require.New(t) - m, err := generateMetaDataV11("http://localhost", "v1.0.1", "xx:xx:xx:xx:xx", "create", - "/dev/sda", "192.168.1.100", "token", "password", "v1.0.2", []string{"8.8.8.8"}, []string{"abc"}) - assert.NoError(err, "no error should have occured") - assert.Contains(m, "harvester.install.mode=create", "expected to find create mode in metadata") - assert.Contains(m, "hwAddr:xx:xx:xx:xx:xx", "expected to find mac address in metadata") - assert.Contains(m, "scheme_version", "expected to find scheme_version") + cloudConfig, err := generateCloudConfig("file:///testdata/create.yaml", "ab:cd:ef:gh:ij:kl", "join", "192.168.1.100", "token", "password", "192.168.1.101", "255.255.255.0", "192.168.1.1", []string{"8.8.8.8"}, []string{"ssh-key 1", "ssh-key 2"}, nil, "http://imagestore/iso", "v1.2.1", "http://seeder-endpoint", "sample", "harvester-system", false, true, 1, "amd64", "/dev/vda", "test") + assert.NoError(err) + hc := config.NewHarvesterConfig() + err = yaml.Unmarshal([]byte(cloudConfig), hc) + assert.NoError(err) + assert.True(hc.Install.Automatic, "expected automatic installation to be set") + assert.NotEmpty(hc.ServerURL, "expected serverURL to be empty") + assert.Equal(hc.Install.Mode, "join", "expected install mode to be create") + assert.Len(hc.Install.ManagementInterface.Interfaces, 1, "expected to find 1 interface defined") + assert.Empty(hc.Install.ConfigURL, "expected configURL to be set") + assert.NotEmpty(hc.OS.Password, "expected password to be set") + assert.Len(hc.OS.DNSNameservers, 1, "expected to find 1 dns server") + assert.Len(hc.OS.SSHAuthorizedKeys, 2, "expected to find 2 ssh keys specified") + assert.NotEmpty(hc.Install.ManagementInterface.IP, "expected IP to be set") + assert.NotEmpty(hc.Install.ManagementInterface.Gateway, "expected gateway to be set") + assert.NotEmpty(hc.Install.ManagementInterface.SubnetMask, "expected subnet mask to be set") + assert.True(hc.Install.WipeDisks, "expected wipe disks to be set") } var ( @@ -76,7 +104,7 @@ var ( Namespace: "default", }, Spec: seederv1alpha1.ClusterSpec{ - HarvesterVersion: "v1.0.1", + HarvesterVersion: "v1.2.0", VIPConfig: seederv1alpha1.VIPConfig{ AddressPoolReference: seederv1alpha1.ObjectReference{ Name: "management-pool", @@ -105,7 +133,7 @@ var ( "8.8.8.8", "8.8.4.4", }, - ConfigURL: "http://endpoint", + ConfigURL: "file:///testdata/create.yaml", }, }, Status: seederv1alpha1.ClusterStatus{ @@ -113,69 +141,193 @@ var ( ClusterAddress: "192.168.1.100", }, } + + svc = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-svc", + Namespace: "harvester-system", + }, + Spec: v1.ServiceSpec{}, + Status: v1.ServiceStatus{ + LoadBalancer: v1.LoadBalancerStatus{ + Ingress: []v1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + }, + }, + }, + }, + } + + hegelSvc = &v1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "hegel-svc", + Namespace: "harvester-system", + }, + Spec: v1.ServiceSpec{}, + Status: v1.ServiceStatus{ + LoadBalancer: v1.LoadBalancerStatus{ + Ingress: []v1.LoadBalancerIngress{ + { + IP: "127.0.0.1", + }, + }, + }, + }, + } ) -func Test_GenerateHWRequestV10(t *testing.T) { +func Test_GenerateHWRequest(t *testing.T) { assert := require.New(t) util.CreateOrUpdateCondition(i, seederv1alpha1.HarvesterCreateNode, "") - hw, err := GenerateHWRequest(i, c) - t.Log(i.Status) - assert.NoError(err, "no error should occur during hardware generation") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.mode=create", "expected to find create mode in metadata") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "hwAddr:xx:xx:xx:xx:xx", "expected to find mac address in metadata") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "dns_nameservers=8.8.8.8", "expected to find correct nameserver") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "ssh_authorized_keys=\\\"- abc ", "expected to find ssh_keys") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "token=token", "expected to find token") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "password=password", "expected to find password") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.vip=192.168.1.100", "expected to find a vip") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.vip_mode=static", "expected to find vipMode static") - assert.Equal(hw.Spec.Interfaces[0].DHCP.MAC, i.Spec.ManagementInterfaceMacAddress, "expected to find correct hardware address") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Gateway, i.Status.Gateway, "expected to find correct gateway") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Address, i.Status.Address, "expected to find correct address") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Netmask, i.Status.Netmask, "expected to find correct netmask") - assert.NotContains(hw.Spec.Metadata.Instance.Userdata, "scheme_version") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.networks.harvester-mgmt", "expected to find harvester-mgmt in interfaces") - assert.NotContains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.management_interface", "expected to not find management_interface") + hw, err := GenerateHWRequest(i, c, svc, hegelSvc) + assert.NoError(err, "expected no error during hardware generation") + assert.NotNil(hw.Spec.UserData, "expected user data to be set") } -func Test_GenerateHWRequestV11(t *testing.T) { +func Test_GenerateWorkflow(t *testing.T) { assert := require.New(t) - clusterCopy := c.DeepCopy() - clusterCopy.Spec.HarvesterVersion = "v1.1.0" - util.CreateOrUpdateCondition(i, seederv1alpha1.HarvesterCreateNode, "") - hw, err := GenerateHWRequest(i, clusterCopy) - assert.NoError(err, "no error should occur during hardware generation") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.mode=create", "expected to find create mode in metadata") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "hwAddr:xx:xx:xx:xx:xx", "expected to find mac address in metadata") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "dns_nameservers=8.8.8.8", "expected to find correct nameserver") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "ssh_authorized_keys=\\\"- abc ", "expected to find ssh_keys") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "token=token", "expected to find token") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "password=password", "expected to find password") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.vip=192.168.1.100", "expected to find a vip") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.vip_mode=static", "expected to find vipMode static") - assert.Equal(hw.Spec.Interfaces[0].DHCP.MAC, i.Spec.ManagementInterfaceMacAddress, "expected to find correct hardware address") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Gateway, i.Status.Gateway, "expected to find correct gateway") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Address, i.Status.Address, "expected to find correct address") - assert.Equal(hw.Spec.Interfaces[0].DHCP.IP.Netmask, i.Status.Netmask, "expected to find correct netmask") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "scheme_version") - assert.NotContains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.networks.harvester-mgmt", "expected to find harvester-mgmt in interfaces") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.install.management_interface", "expected to not find management_interface") + var testCases = []struct { + name string + i *seederv1alpha1.Inventory + c *seederv1alpha1.Cluster + expectedWorkflow *tinkv1alpha1.Workflow + }{ + { + name: "default workflow", + i: &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + Namespace: "harvester-system", + }, + Spec: seederv1alpha1.InventorySpec{ + ManagementInterfaceMacAddress: "xx:xx", + }, + }, + c: &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "harvester-system", + }, + }, + expectedWorkflow: &tinkv1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + Namespace: "harvester-system", + }, + Spec: tinkv1alpha1.WorkflowSpec{ + TemplateRef: "test-node", + HardwareRef: "test-node", + HardwareMap: map[string]string{ + "device_1": "xx:xx", + }, + }, + }, + }, { + name: "custom workflow", + i: &seederv1alpha1.Inventory{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + Namespace: "harvester-system", + }, + Spec: seederv1alpha1.InventorySpec{ + ManagementInterfaceMacAddress: "xx:xx", + }, + }, + c: &seederv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-cluster", + Namespace: "harvester-system", + }, + Spec: seederv1alpha1.ClusterSpec{ + ClusterConfig: seederv1alpha1.ClusterConfig{ + CustomProvisioningTemplate: "override-template", + }, + }, + }, + expectedWorkflow: &tinkv1alpha1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + Namespace: "harvester-system", + }, + Spec: tinkv1alpha1.WorkflowSpec{ + TemplateRef: "override-template", + HardwareRef: "test-node", + HardwareMap: map[string]string{ + "device_1": "xx:xx", + }, + }, + }, + }, + } + + for _, v := range testCases { + generatedWorkflow := GenerateWorkflow(v.i, v.c) + assert.Equal(v.expectedWorkflow, generatedWorkflow, fmt.Sprintf("expected generatedWorkflow to match expected workflow for case %s", v.name)) + } +} + +func Test_generateIPXEScript(t *testing.T) { + assert := require.New(t) + _, err := generateIPXEScript("v1.1.3", "http://imagestore/iso", "hegelEndpoint", "ab:cd:ef:gh:ij", "amd64") + assert.NoError(err, "expect no error during generation of ipxe script") +} + +func Test_GenerateHardwareRequestV11(t *testing.T) { + assert := require.New(t) + cObj := c.DeepCopy() + cObj.Spec.HarvesterVersion = "v1.1.2" + hw, err := GenerateHWRequest(i, cObj, svc, hegelSvc) + assert.NoError(err, "expected no error during hardware generation") + assert.NotNil(hw.Spec.UserData, "expected user data to be set") + for _, v := range hw.Spec.Interfaces { + assert.NotNil(v.Netboot.IPXE, "expect ipxe definition to exist") + assert.NotEmpty(v.Netboot.IPXE.Contents, "expected content script to be defined") + } } -func Test_GenerateHWRequestWithJoinV10(t *testing.T) { +func Test_createModeCloudConfigV11(t *testing.T) { assert := require.New(t) - util.RemoveCondition(i, seederv1alpha1.HarvesterCreateNode) - hw, err := GenerateHWRequest(i, c) - assert.NoError(err, "no error should occur during hardware generation") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.server_url=https://192.168.1.100:8443", "expected to find join url") + cloudConfig, err := generateCloudConfig("file:///testdata/create.yaml", "ab:cd:ef:gh:ij:kl", "create", "192.168.1.100", "token", "password", "192.168.1.101", "255.255.255.0", "192.168.1.1", []string{"8.8.8.8"}, []string{"ssh-key 1", "ssh-key 2"}, nil, "http://imagestore/iso", "v1.1.2", "http://seeder-endpoint", "sample", "harvester-system", false, true, 1, "amd64", "/dev/vda", "test") + assert.NoError(err) + hc := config.NewHarvesterConfig() + err = yaml.Unmarshal([]byte(cloudConfig), hc) + assert.NoError(err) + assert.True(hc.Install.Automatic, "expected automatic installation to be set") + assert.Empty(hc.ServerURL, "expected serverURL to be empty") + assert.NotEmpty(hc.Install.Vip, "expected VIP to be set") + assert.Equal(hc.Install.VipMode, "static", "expected vip mode to be static") + assert.Equal(hc.Install.Mode, "create", "expected install mode to be create") + assert.Len(hc.Install.ManagementInterface.Interfaces, 1, "expected to find 1 interface defined") + assert.Empty(hc.Install.ConfigURL, "expected configURL to be empty") + assert.NotEmpty(hc.OS.Password, "expected password to be set") + assert.Len(hc.OS.DNSNameservers, 1, "expected to find 1 dns server") + assert.Len(hc.OS.SSHAuthorizedKeys, 2, "expected to find 2 ssh keys specified") + assert.Len(hc.Install.Webhooks, 1, "expected to find atleast 1 webhook definition") + assert.NotEmpty(hc.Install.ManagementInterface.IP, "expected IP to be set") + assert.NotEmpty(hc.Install.ManagementInterface.Gateway, "expected gateway to be set") + assert.NotEmpty(hc.Install.ManagementInterface.SubnetMask, "expected subnet mask to be set") + assert.True(hc.Install.WipeDisks, "expected wipe disks to be set") } -func Test_GenerateHWRequestWithJoinV11(t *testing.T) { +func Test_joinModeCloudConfigV11(t *testing.T) { assert := require.New(t) - util.RemoveCondition(i, seederv1alpha1.HarvesterCreateNode) - clusterCopy := c.DeepCopy() - clusterCopy.Spec.HarvesterVersion = "v1.1.0" - hw, err := GenerateHWRequest(i, clusterCopy) - assert.NoError(err, "no error should occur during hardware generation") - assert.Contains(hw.Spec.Metadata.Instance.Userdata, "harvester.server_url=https://192.168.1.100", "expected to find join url") + cloudConfig, err := generateCloudConfig("file:///testdata/create.yaml", "ab:cd:ef:gh:ij:kl", "join", "192.168.1.100", "token", "password", "192.168.1.101", "255.255.255.0", "192.168.1.1", []string{"8.8.8.8"}, []string{"ssh-key 1", "ssh-key 2"}, nil, "http://imagestore/iso", "v1.1.2", "http://seeder-endpoint", "sample", "harvester-system", false, true, 1, "amd64", "/dev/vda", "test") + assert.NoError(err) + hc := config.NewHarvesterConfig() + err = yaml.Unmarshal([]byte(cloudConfig), hc) + assert.NoError(err) + assert.True(hc.Install.Automatic, "expected automatic installation to be set") + assert.NotEmpty(hc.ServerURL, "expected serverURL to be empty") + assert.Equal(hc.Install.Mode, "join", "expected install mode to be create") + assert.Len(hc.Install.ManagementInterface.Interfaces, 1, "expected to find 1 interface defined") + assert.Empty(hc.Install.ConfigURL, "expected configURL to be empty") + assert.NotEmpty(hc.OS.Password, "expected password to be set") + assert.Len(hc.OS.DNSNameservers, 1, "expected to find 1 dns server") + assert.Len(hc.OS.SSHAuthorizedKeys, 2, "expected to find 2 ssh keys specified") + assert.Len(hc.Install.Webhooks, 1, "expected to find atleast 1 webhook definition") + assert.NotEmpty(hc.Install.ManagementInterface.IP, "expected IP to be set") + assert.NotEmpty(hc.Install.ManagementInterface.Gateway, "expected gateway to be set") + assert.NotEmpty(hc.Install.ManagementInterface.SubnetMask, "expected subnet mask to be set") + assert.True(hc.Install.WipeDisks, "expected wipe disks to be set") } diff --git a/pkg/tink/types.go b/pkg/tink/types.go new file mode 100644 index 0000000..9b8411b --- /dev/null +++ b/pkg/tink/types.go @@ -0,0 +1,81 @@ +package tink + +// struct copied from https://github.com/tinkerbell/tink/blob/main/internal/workflow/types.go +// since they are internal packages this makes it harder to reuse these for generating templates +// Workflow represents a workflow to be executed. +type Workflow struct { + Version string `yaml:"version"` + Name string `yaml:"name"` + ID string `yaml:"id"` + GlobalTimeout int `yaml:"global_timeout"` + Tasks []Task `yaml:"tasks"` +} + +// Task represents a task to be executed as part of a workflow. +type Task struct { + Name string `yaml:"name"` + WorkerAddr string `yaml:"worker"` + Actions []Action `yaml:"actions"` + Volumes []string `yaml:"volumes,omitempty"` + Environment map[string]string `yaml:"environment,omitempty"` +} + +// Action is the basic executional unit for a workflow. +type Action struct { + Name string `yaml:"name"` + Image string `yaml:"image"` + Timeout int64 `yaml:"timeout"` + Command []string `yaml:"command,omitempty"` + OnTimeout []string `yaml:"on-timeout,omitempty"` + OnFailure []string `yaml:"on-failure,omitempty"` + Volumes []string `yaml:"volumes,omitempty"` + Environment map[string]string `yaml:"environment,omitempty"` + Pid string `yaml:"pid,omitempty"` +} + +const ( + HarvesterDevice = "HARVESTER_DEVICE" + DestDisk = "DEST_DISK" + HarvesterCloudInitURL = "HARVESTER_STREAMDISK_CLOUDINIT_URL" + ImageURL = "IMG_URL" +) + +var ( + DefaultHarvesterInstallationWorkflow = Workflow{ + Name: "harvester-installation", + Version: "0.1", + GlobalTimeout: 36000, + } + + DefaultInstallationTask = Task{ + Name: "harvester-os-installation", + WorkerAddr: "{{.device_1}}", + Volumes: []string{"/dev:/dev", "/dev/console:/dev/console", "/lib/firmware:/lib/firmware"}, + } + DefaultStreamHarvesterAction = Action{ + Name: "stream-harvester", + Image: "gmehta3/image2disk:dev", + Timeout: 3000, + Environment: map[string]string{ + "COMPRESSED": "true", + DestDisk: "", // inventory disk info where image is copied to + ImageURL: "", // location where raw.gz image artifact is stored + }, + } + DefaultConfigureHarvesterAction = Action{ + Name: "configure-harvester", + Image: "gmehta3/configure-harvester:latest", + Timeout: 90, + Environment: map[string]string{ + "HARVESTER_TTY": "tty1", + HarvesterDevice: "", // inventory disk info, where image is installed + HarvesterCloudInitURL: "", // hegel endopint reference + }, + } + DefaultRebootNodeAction = Action{ + Name: "reboot-harvester", + Image: "gmehta3/reboot:latest", + Timeout: 90, + Volumes: []string{"/worker:/worker"}, + } +) diff --git a/pkg/util/client_test.go b/pkg/util/client_test.go index 2ed8f1c..292d8cd 100644 --- a/pkg/util/client_test.go +++ b/pkg/util/client_test.go @@ -14,6 +14,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" typedCore "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/clientcmd" + runtimelog "sigs.k8s.io/controller-runtime/pkg/log" ) var k3sNodeAddress string @@ -68,6 +69,13 @@ func TestMain(t *testing.M) { k3sNodeAddress = k3s.GetIPInNetwork(&networks[0]) time.Sleep(60 * time.Second) + // needed to pass check in controller-runtime https://github.com/kubernetes-sigs/controller-runtime/commit/ed8be90b87613a10303ff8a74e9452bb47e77bf7 + + runtimelog.SetLogger(l) + if err != nil { + _ = pool.Purge(k3s) + log.Fatal(err) + } code := t.Run() _ = pool.Purge(k3s) os.Exit(code) diff --git a/pkg/util/inventory_test.go b/pkg/util/inventory_test.go index 2b93bce..322e19d 100644 --- a/pkg/util/inventory_test.go +++ b/pkg/util/inventory_test.go @@ -4,14 +4,13 @@ import ( "context" "testing" + seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" + "github.com/harvester/seeder/pkg/mock" "github.com/stretchr/testify/require" rufio "github.com/tinkerbell/rufio/api/v1alpha1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/log/zap" - - seederv1alpha1 "github.com/harvester/seeder/pkg/api/v1alpha1" - "github.com/harvester/seeder/pkg/mock" ) var ( diff --git a/pkg/util/job.go b/pkg/util/job.go index b328fae..402fd27 100644 --- a/pkg/util/job.go +++ b/pkg/util/job.go @@ -19,13 +19,21 @@ func GenerateJob(name, namespace, powerAction string) *rufio.Job { PowerAction: rufio.PowerOn.Ptr(), } + pxeBoot := rufio.Action{ + OneTimeBootDeviceAction: &rufio.OneTimeBootDeviceAction{ + Devices: []rufio.BootDevice{ + rufio.PXE, + }, + }, + } + switch powerAction { case seederv1alpha1.NodePowerActionPowerOn: tasks = append(tasks, powerOnTask) case seederv1alpha1.NodePowerActionShutdown: tasks = append(tasks, powerOffTask) case seederv1alpha1.NodePowerActionReboot: - tasks = append(tasks, powerOffTask, powerOnTask) + tasks = append(tasks, powerOffTask, pxeBoot, powerOnTask) default: return nil } diff --git a/scripts/ci b/scripts/ci index 339a26d..aa269fe 100755 --- a/scripts/ci +++ b/scripts/ci @@ -5,4 +5,5 @@ cd $(dirname $0) ./validate ./test -./build \ No newline at end of file +./build +./package \ No newline at end of file diff --git a/scripts/quick b/scripts/quick new file mode 100755 index 0000000..6d1c3a8 --- /dev/null +++ b/scripts/quick @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +cd $(dirname $0) +./build +./package \ No newline at end of file diff --git a/scripts/validate b/scripts/validate index 7ea8c9a..3bb39dd 100755 --- a/scripts/validate +++ b/scripts/validate @@ -15,4 +15,4 @@ if [[ -z "$(command -v golangci-lint)" ]]; then fi echo "Running: golangci-lint run" -golangci-lint run --timeout 10m \ No newline at end of file +golangci-lint run --timeout 5m