mirror of
https://github.com/jlengrand/engine.git
synced 2026-03-10 08:11:21 +00:00
chore(ENG_1123_update_cert_manager): update chart manager (#623)
This commit is contained in:
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -2115,6 +2115,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"sysinfo",
|
||||
@@ -2965,6 +2966,18 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"ryu",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
@@ -4211,6 +4224,15 @@ version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.1"
|
||||
|
||||
@@ -55,6 +55,8 @@ tera = "1.10.0"
|
||||
serde = "1.0.126"
|
||||
serde_json = "1.0.64"
|
||||
serde_derive = "1.0.126"
|
||||
serde_yaml = "0.8.23"
|
||||
|
||||
# AWS deps
|
||||
tokio = { version = "1.10.0", features = ["full"] }
|
||||
rusoto_core = "0.47.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v1
|
||||
appVersion: v1.1.1
|
||||
appVersion: v1.2.0
|
||||
description: A Helm chart for cert-manager
|
||||
home: https://github.com/jetstack/cert-manager
|
||||
icon: https://raw.githubusercontent.com/jetstack/cert-manager/master/logo/logo.png
|
||||
@@ -14,4 +14,4 @@ maintainers:
|
||||
name: cert-manager
|
||||
sources:
|
||||
- https://github.com/jetstack/cert-manager
|
||||
version: v1.1.1
|
||||
version: v1.2.0
|
||||
|
||||
@@ -19,16 +19,9 @@ Before installing the chart, you must first install the cert-manager CustomResou
|
||||
This is performed in a separate step to allow you to easily uninstall and reinstall cert-manager without deleting your installed custom resources.
|
||||
|
||||
```bash
|
||||
# Kubernetes 1.15+
|
||||
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.1.1/cert-manager.crds.yaml
|
||||
|
||||
# Kubernetes <1.15
|
||||
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.1.1/cert-manager-legacy.crds.yaml
|
||||
$ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.2.0/cert-manager.crds.yaml
|
||||
```
|
||||
|
||||
> **Note**: If you're using a Kubernetes version below `v1.15` you will need to install the legacy version of the custom resource definitions.
|
||||
> This version does not have API version conversion enabled and only supports `cert-manager.io/v1` API resources.
|
||||
|
||||
To install the chart with the release name `my-release`:
|
||||
|
||||
```console
|
||||
@@ -72,11 +65,7 @@ If you want to completely uninstall cert-manager from your cluster, you will als
|
||||
delete the previously installed CustomResourceDefinition resources:
|
||||
|
||||
```console
|
||||
# Kubernetes 1.15+
|
||||
$ kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/v1.1.1/cert-manager.crds.yaml
|
||||
|
||||
# Kubernetes <1.15
|
||||
$ kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/v1.1.1/cert-manager-legacy.crds.yaml
|
||||
$ kubectl delete -f https://github.com/jetstack/cert-manager/releases/download/v1.2.0/cert-manager.crds.yaml
|
||||
```
|
||||
|
||||
## Configuration
|
||||
@@ -91,9 +80,12 @@ The following table lists the configurable parameters of the cert-manager chart
|
||||
| `global.podSecurityPolicy.enabled` | If `true`, create and use PodSecurityPolicy (includes sub-charts) | `false` |
|
||||
| `global.podSecurityPolicy.useAppArmor` | If `true`, use Apparmor seccomp profile in PSP | `true` |
|
||||
| `global.leaderElection.namespace` | Override the namespace used to store the ConfigMap for leader election | `kube-system` |
|
||||
| `global.leaderElection.leaseDuration` | The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate | |
|
||||
| `global.leaderElection.renewDeadline` | The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration | |
|
||||
| `global.leaderElection.retryPeriod` | The duration the clients should wait between attempting acquisition and renewal of a leadership | |
|
||||
| `installCRDs` | If true, CRD resources will be installed as part of the Helm chart. If enabled, when uninstalling CRD resources will be deleted causing all installed custom resources to be DELETED | `false` |
|
||||
| `image.repository` | Image repository | `quay.io/jetstack/cert-manager-controller` |
|
||||
| `image.tag` | Image tag | `v1.1.1` |
|
||||
| `image.tag` | Image tag | `v1.2.0` |
|
||||
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
|
||||
| `replicaCount` | Number of cert-manager replicas | `1` |
|
||||
| `clusterResourceNamespace` | Override the namespace used to store DNS provider credentials etc. for ClusterIssuer resources | Same namespace as cert-manager pod |
|
||||
@@ -148,7 +140,7 @@ The following table lists the configurable parameters of the cert-manager chart
|
||||
| `webhook.affinity` | Node affinity for webhook pod assignment | `{}` |
|
||||
| `webhook.tolerations` | Node tolerations for webhook pod assignment | `[]` |
|
||||
| `webhook.image.repository` | Webhook image repository | `quay.io/jetstack/cert-manager-webhook` |
|
||||
| `webhook.image.tag` | Webhook image tag | `v1.1.1` |
|
||||
| `webhook.image.tag` | Webhook image tag | `v1.2.0` |
|
||||
| `webhook.image.pullPolicy` | Webhook image pull policy | `IfNotPresent` |
|
||||
| `webhook.securePort` | The port that the webhook should listen on for requests. | `10250` |
|
||||
| `webhook.securityContext` | Security context for webhook pod assignment | `{}` |
|
||||
@@ -178,7 +170,7 @@ The following table lists the configurable parameters of the cert-manager chart
|
||||
| `cainjector.affinity` | Node affinity for cainjector pod assignment | `{}` |
|
||||
| `cainjector.tolerations` | Node tolerations for cainjector pod assignment | `[]` |
|
||||
| `cainjector.image.repository` | cainjector image repository | `quay.io/jetstack/cert-manager-cainjector` |
|
||||
| `cainjector.image.tag` | cainjector image tag | `v1.1.1` |
|
||||
| `cainjector.image.tag` | cainjector image tag | `v1.2.0` |
|
||||
| `cainjector.image.pullPolicy` | cainjector image pull policy | `IfNotPresent` |
|
||||
| `cainjector.securityContext` | Security context for cainjector pod assignment | `{}` |
|
||||
| `cainjector.containerSecurityContext` | Security context to be set on cainjector component container | `{}` |
|
||||
|
||||
@@ -61,7 +61,18 @@ spec:
|
||||
{{- if .Values.global.logLevel }}
|
||||
- --v={{ .Values.global.logLevel }}
|
||||
{{- end }}
|
||||
- --leader-election-namespace={{ .Values.global.leaderElection.namespace }}
|
||||
{{- with .Values.global.leaderElection }}
|
||||
- --leader-election-namespace={{ .namespace }}
|
||||
{{- if .leaseDuration }}
|
||||
- --leader-election-lease-duration={{ .leaseDuration }}
|
||||
{{- end }}
|
||||
{{- if .renewDeadline }}
|
||||
- --leader-election-renew-deadline={{ .renewDeadline }}
|
||||
{{- end }}
|
||||
{{- if .retryPeriod }}
|
||||
- --leader-election-retry-period={{ .retryPeriod }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.cainjector.extraArgs }}
|
||||
{{ toYaml .Values.cainjector.extraArgs | indent 10 }}
|
||||
{{- end }}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
||||
{{- if (semverCompare ">=1.16-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
{{- if .Values.installCRDs }}
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
@@ -22,6 +21,8 @@ spec:
|
||||
- cr
|
||||
- crs
|
||||
singular: certificaterequest
|
||||
categories:
|
||||
- cert-manager
|
||||
scope: Namespaced
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -56,7 +57,7 @@ spec:
|
||||
type: date
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a 'one-shot' resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
type: object
|
||||
properties:
|
||||
apiVersion:
|
||||
@@ -85,7 +86,7 @@ spec:
|
||||
description: IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to 'cert-manager.io' if empty.
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to `cert-manager.io` if empty.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -162,14 +163,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', 'InvalidRequest').
|
||||
description: Type of the condition, known values are (`Ready`, `InvalidRequest`).
|
||||
type: string
|
||||
failureTime:
|
||||
description: FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off.
|
||||
@@ -198,7 +199,7 @@ spec:
|
||||
type: date
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a 'one-shot' resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
type: object
|
||||
properties:
|
||||
apiVersion:
|
||||
@@ -227,7 +228,7 @@ spec:
|
||||
description: IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to 'cert-manager.io' if empty.
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to `cert-manager.io` if empty.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -304,14 +305,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', 'InvalidRequest').
|
||||
description: Type of the condition, known values are (`Ready`, `InvalidRequest`).
|
||||
type: string
|
||||
failureTime:
|
||||
description: FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off.
|
||||
@@ -340,7 +341,7 @@ spec:
|
||||
type: date
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a 'one-shot' resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
@@ -367,7 +368,7 @@ spec:
|
||||
description: IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to 'cert-manager.io' if empty.
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to `cert-manager.io` if empty.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -448,14 +449,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', 'InvalidRequest').
|
||||
description: Type of the condition, known values are (`Ready`, `InvalidRequest`).
|
||||
type: string
|
||||
failureTime:
|
||||
description: FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off.
|
||||
@@ -484,7 +485,7 @@ spec:
|
||||
type: date
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a 'one-shot' resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
description: "A CertificateRequest is used to request a signed certificate from one of the configured issuers. \n All fields within the CertificateRequest's `spec` are immutable after creation. A CertificateRequest will either succeed or fail, as denoted by its `status.state` field. \n A CertificateRequest is a one-shot resource, meaning it represents a single point in time request for a certificate and cannot be re-used."
|
||||
type: object
|
||||
required:
|
||||
- spec
|
||||
@@ -511,7 +512,7 @@ spec:
|
||||
description: IsCA will request to mark the certificate as valid for certificate signing when submitting to the issuer. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to 'cert-manager.io' if empty.
|
||||
description: IssuerRef is a reference to the issuer for this CertificateRequest. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the CertificateRequest will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times. The group field refers to the API group of the issuer which defaults to `cert-manager.io` if empty.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -592,14 +593,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', 'InvalidRequest').
|
||||
description: Type of the condition, known values are (`Ready`, `InvalidRequest`).
|
||||
type: string
|
||||
failureTime:
|
||||
description: FailureTime stores the time that this CertificateRequest failed. This is used to influence garbage collection and back-off.
|
||||
@@ -636,6 +637,8 @@ spec:
|
||||
- cert
|
||||
- certs
|
||||
singular: certificate
|
||||
categories:
|
||||
- cert-manager
|
||||
scope: Namespaced
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -719,7 +722,7 @@ spec:
|
||||
description: IsCA will mark this Certificate as valid for certificate signing. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the Certificate will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times.
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the Certificate will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -734,19 +737,19 @@ spec:
|
||||
description: Name of the resource being referred to.
|
||||
type: string
|
||||
keyAlgorithm:
|
||||
description: KeyAlgorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either "rsa" or "ecdsa" If `keyAlgorithm` is specified and `keySize` is not provided, key size of 256 will be used for "ecdsa" key algorithm and key size of 2048 will be used for "rsa" key algorithm.
|
||||
description: KeyAlgorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `rsa` or `ecdsa` If `keyAlgorithm` is specified and `keySize` is not provided, key size of 256 will be used for `ecdsa` key algorithm and key size of 2048 will be used for `rsa` key algorithm.
|
||||
type: string
|
||||
enum:
|
||||
- rsa
|
||||
- ecdsa
|
||||
keyEncoding:
|
||||
description: KeyEncoding is the private key cryptography standards (PKCS) for this certificate's private key to be encoded in. If provided, allowed values are "pkcs1" and "pkcs8" standing for PKCS#1 and PKCS#8, respectively. If KeyEncoding is not specified, then PKCS#1 will be used by default.
|
||||
description: KeyEncoding is the private key cryptography standards (PKCS) for this certificate's private key to be encoded in. If provided, allowed values are `pkcs1` and `pkcs8` standing for PKCS#1 and PKCS#8, respectively. If KeyEncoding is not specified, then `pkcs1` will be used by default.
|
||||
type: string
|
||||
enum:
|
||||
- pkcs1
|
||||
- pkcs8
|
||||
keySize:
|
||||
description: KeySize is the key bit size of the corresponding private key for this certificate. If `keyAlgorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `keyAlgorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. No other values are allowed.
|
||||
description: KeySize is the key bit size of the corresponding private key for this certificate. If `keyAlgorithm` is set to `rsa`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `keyAlgorithm` is set to `ecdsa`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. No other values are allowed.
|
||||
type: integer
|
||||
keystores:
|
||||
description: Keystores configures additional keystore output formats stored in the `secretName` Secret resource.
|
||||
@@ -911,14 +914,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', `Issuing`).
|
||||
description: Type of the condition, known values are (`Ready`, `Issuing`).
|
||||
type: string
|
||||
lastFailureTime:
|
||||
description: LastFailureTime is the time as recorded by the Certificate controller of the most recent failure to complete a CertificateRequest for this Certificate resource. If set, cert-manager will not re-request another Certificate until 1 hour has elapsed from this time.
|
||||
@@ -1014,7 +1017,7 @@ spec:
|
||||
description: IsCA will mark this Certificate as valid for certificate signing. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the Certificate will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times.
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the Certificate will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -1029,19 +1032,19 @@ spec:
|
||||
description: Name of the resource being referred to.
|
||||
type: string
|
||||
keyAlgorithm:
|
||||
description: KeyAlgorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either "rsa" or "ecdsa" If `keyAlgorithm` is specified and `keySize` is not provided, key size of 256 will be used for "ecdsa" key algorithm and key size of 2048 will be used for "rsa" key algorithm.
|
||||
description: KeyAlgorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `rsa` or `ecdsa` If `keyAlgorithm` is specified and `keySize` is not provided, key size of 256 will be used for `ecdsa` key algorithm and key size of 2048 will be used for `rsa` key algorithm.
|
||||
type: string
|
||||
enum:
|
||||
- rsa
|
||||
- ecdsa
|
||||
keyEncoding:
|
||||
description: KeyEncoding is the private key cryptography standards (PKCS) for this certificate's private key to be encoded in. If provided, allowed values are "pkcs1" and "pkcs8" standing for PKCS#1 and PKCS#8, respectively. If KeyEncoding is not specified, then PKCS#1 will be used by default.
|
||||
description: KeyEncoding is the private key cryptography standards (PKCS) for this certificate's private key to be encoded in. If provided, allowed values are `pkcs1` and `pkcs8` standing for PKCS#1 and PKCS#8, respectively. If KeyEncoding is not specified, then `pkcs1` will be used by default.
|
||||
type: string
|
||||
enum:
|
||||
- pkcs1
|
||||
- pkcs8
|
||||
keySize:
|
||||
description: KeySize is the key bit size of the corresponding private key for this certificate. If `keyAlgorithm` is set to `RSA`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `keyAlgorithm` is set to `ECDSA`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. No other values are allowed.
|
||||
description: KeySize is the key bit size of the corresponding private key for this certificate. If `keyAlgorithm` is set to `rsa`, valid values are `2048`, `4096` or `8192`, and will default to `2048` if not specified. If `keyAlgorithm` is set to `ecdsa`, valid values are `256`, `384` or `521`, and will default to `256` if not specified. No other values are allowed.
|
||||
type: integer
|
||||
keystores:
|
||||
description: Keystores configures additional keystore output formats stored in the `secretName` Secret resource.
|
||||
@@ -1055,7 +1058,7 @@ spec:
|
||||
- passwordSecretRef
|
||||
properties:
|
||||
create:
|
||||
description: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance.
|
||||
description: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance. A file named `truststore.jks` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority.
|
||||
type: boolean
|
||||
passwordSecretRef:
|
||||
description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the JKS keystore.
|
||||
@@ -1077,7 +1080,7 @@ spec:
|
||||
- passwordSecretRef
|
||||
properties:
|
||||
create:
|
||||
description: Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance.
|
||||
description: Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance. A file named `truststore.p12` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority.
|
||||
type: boolean
|
||||
passwordSecretRef:
|
||||
description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the PKCS12 keystore.
|
||||
@@ -1206,14 +1209,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', `Issuing`).
|
||||
description: Type of the condition, known values are (`Ready`, `Issuing`).
|
||||
type: string
|
||||
lastFailureTime:
|
||||
description: LastFailureTime is the time as recorded by the Certificate controller of the most recent failure to complete a CertificateRequest for this Certificate resource. If set, cert-manager will not re-request another Certificate until 1 hour has elapsed from this time.
|
||||
@@ -1311,7 +1314,7 @@ spec:
|
||||
description: IsCA will mark this Certificate as valid for certificate signing. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the Certificate will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times.
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the Certificate will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -1378,13 +1381,13 @@ spec:
|
||||
type: object
|
||||
properties:
|
||||
algorithm:
|
||||
description: Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either "rsa" or "ecdsa" If `algorithm` is specified and `size` is not provided, key size of 256 will be used for "ecdsa" key algorithm and key size of 2048 will be used for "rsa" key algorithm.
|
||||
description: Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm.
|
||||
type: string
|
||||
enum:
|
||||
- RSA
|
||||
- ECDSA
|
||||
encoding:
|
||||
description: The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are "pkcs1" and "pkcs8" standing for PKCS#1 and PKCS#8, respectively. Defaults to PKCS#1 if not specified.
|
||||
description: The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified.
|
||||
type: string
|
||||
enum:
|
||||
- PKCS1
|
||||
@@ -1503,14 +1506,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', `Issuing`).
|
||||
description: Type of the condition, known values are (`Ready`, `Issuing`).
|
||||
type: string
|
||||
lastFailureTime:
|
||||
description: LastFailureTime is the time as recorded by the Certificate controller of the most recent failure to complete a CertificateRequest for this Certificate resource. If set, cert-manager will not re-request another Certificate until 1 hour has elapsed from this time.
|
||||
@@ -1608,7 +1611,7 @@ spec:
|
||||
description: IsCA will mark this Certificate as valid for certificate signing. This will automatically add the `cert sign` usage to the list of `usages`.
|
||||
type: boolean
|
||||
issuerRef:
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the 'kind' field is not set, or set to 'Issuer', an Issuer resource with the given name in the same namespace as the Certificate will be used. If the 'kind' field is set to 'ClusterIssuer', a ClusterIssuer with the provided name will be used. The 'name' field in this stanza is required at all times.
|
||||
description: IssuerRef is a reference to the issuer for this certificate. If the `kind` field is not set, or set to `Issuer`, an Issuer resource with the given name in the same namespace as the Certificate will be used. If the `kind` field is set to `ClusterIssuer`, a ClusterIssuer with the provided name will be used. The `name` field in this stanza is required at all times.
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
@@ -1634,7 +1637,7 @@ spec:
|
||||
- passwordSecretRef
|
||||
properties:
|
||||
create:
|
||||
description: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance.
|
||||
description: Create enables JKS keystore creation for the Certificate. If true, a file named `keystore.jks` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance. A file named `truststore.jks` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority
|
||||
type: boolean
|
||||
passwordSecretRef:
|
||||
description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the JKS keystore.
|
||||
@@ -1656,7 +1659,7 @@ spec:
|
||||
- passwordSecretRef
|
||||
properties:
|
||||
create:
|
||||
description: Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance.
|
||||
description: Create enables PKCS12 keystore creation for the Certificate. If true, a file named `keystore.p12` will be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef`. The keystore file will only be updated upon re-issuance. A file named `truststore.p12` will also be created in the target Secret resource, encrypted using the password stored in `passwordSecretRef` containing the issuing Certificate Authority
|
||||
type: boolean
|
||||
passwordSecretRef:
|
||||
description: PasswordSecretRef is a reference to a key in a Secret resource containing the password used to encrypt the PKCS12 keystore.
|
||||
@@ -1675,13 +1678,13 @@ spec:
|
||||
type: object
|
||||
properties:
|
||||
algorithm:
|
||||
description: Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either "rsa" or "ecdsa" If `algorithm` is specified and `size` is not provided, key size of 256 will be used for "ecdsa" key algorithm and key size of 2048 will be used for "rsa" key algorithm.
|
||||
description: Algorithm is the private key algorithm of the corresponding private key for this certificate. If provided, allowed values are either `RSA` or `ECDSA` If `algorithm` is specified and `size` is not provided, key size of 256 will be used for `ECDSA` key algorithm and key size of 2048 will be used for `RSA` key algorithm.
|
||||
type: string
|
||||
enum:
|
||||
- RSA
|
||||
- ECDSA
|
||||
encoding:
|
||||
description: The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are "pkcs1" and "pkcs8" standing for PKCS#1 and PKCS#8, respectively. Defaults to PKCS#1 if not specified.
|
||||
description: The private key cryptography standards (PKCS) encoding for this certificate's private key to be encoded in. If provided, allowed values are `PKCS1` and `PKCS8` standing for PKCS#1 and PKCS#8, respectively. Defaults to `PKCS1` if not specified.
|
||||
type: string
|
||||
enum:
|
||||
- PKCS1
|
||||
@@ -1800,14 +1803,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready', `Issuing`).
|
||||
description: Type of the condition, known values are (`Ready`, `Issuing`).
|
||||
type: string
|
||||
lastFailureTime:
|
||||
description: LastFailureTime is the time as recorded by the Certificate controller of the most recent failure to complete a CertificateRequest for this Certificate resource. If set, cert-manager will not re-request another Certificate until 1 hour has elapsed from this time.
|
||||
@@ -1859,6 +1862,9 @@ spec:
|
||||
listKind: ChallengeList
|
||||
plural: challenges
|
||||
singular: challenge
|
||||
categories:
|
||||
- cert-manager
|
||||
- cert-manager-acme
|
||||
scope: Namespaced
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -5200,6 +5206,8 @@ spec:
|
||||
listKind: ClusterIssuerList
|
||||
plural: clusterissuers
|
||||
singular: clusterissuer
|
||||
categories:
|
||||
- cert-manager
|
||||
scope: Cluster
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -6043,6 +6051,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -6231,14 +6244,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -7072,6 +7085,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -7260,14 +7278,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -8103,6 +8121,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -8291,14 +8314,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -9134,6 +9157,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -9322,14 +9350,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: true
|
||||
@@ -9359,6 +9387,8 @@ spec:
|
||||
listKind: IssuerList
|
||||
plural: issuers
|
||||
singular: issuer
|
||||
categories:
|
||||
- cert-manager
|
||||
scope: Namespaced
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -10202,6 +10232,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -10390,14 +10425,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -11231,6 +11266,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -11419,14 +11459,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -12262,6 +12302,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -12450,14 +12495,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: false
|
||||
@@ -13293,6 +13338,11 @@ spec:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
ocspServers:
|
||||
description: The OCSP server list is an X.509 v3 extension that defines a list of URLs of OCSP responders. The OCSP responders can be queried for the revocation status of an issued certificate. If not set, the certificate wil be issued with no OCSP servers set. For example, an OCSP server URL could be "http://ocsp.int-x3.letsencrypt.org".
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
secretName:
|
||||
description: SecretName is the name of the secret used to sign Certificates issued by this Issuer.
|
||||
type: string
|
||||
@@ -13481,14 +13531,14 @@ spec:
|
||||
description: Reason is a brief machine readable explanation for the condition's last transition.
|
||||
type: string
|
||||
status:
|
||||
description: Status of the condition, one of ('True', 'False', 'Unknown').
|
||||
description: Status of the condition, one of (`True`, `False`, `Unknown`).
|
||||
type: string
|
||||
enum:
|
||||
- "True"
|
||||
- "False"
|
||||
- Unknown
|
||||
type:
|
||||
description: Type of the condition, known values are ('Ready').
|
||||
description: Type of the condition, known values are (`Ready`).
|
||||
type: string
|
||||
served: true
|
||||
storage: true
|
||||
@@ -13518,6 +13568,9 @@ spec:
|
||||
listKind: OrderList
|
||||
plural: orders
|
||||
singular: order
|
||||
categories:
|
||||
- cert-manager
|
||||
- cert-manager-acme
|
||||
scope: Namespaced
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
@@ -14169,4 +14222,3 @@ status:
|
||||
storedVersions: []
|
||||
---
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -86,7 +86,18 @@ spec:
|
||||
{{- else }}
|
||||
- --cluster-resource-namespace=$(POD_NAMESPACE)
|
||||
{{- end }}
|
||||
- --leader-election-namespace={{ .Values.global.leaderElection.namespace }}
|
||||
{{- with .Values.global.leaderElection }}
|
||||
- --leader-election-namespace={{ .namespace }}
|
||||
{{- if .leaseDuration }}
|
||||
- --leader-election-lease-duration={{ .leaseDuration }}
|
||||
{{- end }}
|
||||
{{- if .renewDeadline }}
|
||||
- --leader-election-renew-deadline={{ .renewDeadline }}
|
||||
{{- end }}
|
||||
{{- if .retryPeriod }}
|
||||
- --leader-election-retry-period={{ .retryPeriod }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.extraArgs }}
|
||||
{{ toYaml .Values.extraArgs | indent 10 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -220,7 +220,7 @@ rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "services"]
|
||||
verbs: ["get", "list", "watch", "create", "delete"]
|
||||
- apiGroups: ["extensions"]
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get", "list", "watch", "create", "delete", "update"]
|
||||
# We require the ability to specify a custom hostname when we are creating
|
||||
@@ -261,13 +261,13 @@ rules:
|
||||
- apiGroups: ["cert-manager.io"]
|
||||
resources: ["certificates", "certificaterequests", "issuers", "clusterissuers"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["extensions"]
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
# We require these rules to support users with the OwnerReferencesPermissionEnforcement
|
||||
# admission controller enabled:
|
||||
# https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement
|
||||
- apiGroups: ["extensions"]
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses/finalizers"]
|
||||
verbs: ["update"]
|
||||
- apiGroups: [""]
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
{{- $isV1AdmissionRegistration := false -}}
|
||||
{{- if (or (not (.Capabilities.APIVersions.Has "admissionregistration.k8s.io/v1")) (.Capabilities.APIVersions.Has "hacking-helm.i-wish-this-wasnt-required.cert-manager.io/force-v1beta1-webhooks") ) }}
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
{{- else }}
|
||||
{{- $isV1AdmissionRegistration = true -}}
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
{{- end }}
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
name: {{ include "webhook.fullname" . }}
|
||||
@@ -33,21 +27,12 @@ webhooks:
|
||||
- UPDATE
|
||||
resources:
|
||||
- "*/*"
|
||||
{{- if $isV1AdmissionRegistration }}
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
timeoutSeconds: {{ .Values.webhook.timeoutSeconds }}
|
||||
{{- end }}
|
||||
failurePolicy: Fail
|
||||
{{- if (semverCompare ">=1.12-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
# Only include 'sideEffects' field in Kubernetes 1.12+
|
||||
sideEffects: None
|
||||
{{- end }}
|
||||
clientConfig:
|
||||
{{- if (semverCompare "<=1.12-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
# Set caBundle to empty to avoid https://github.com/kubernetes/kubernetes/pull/70138
|
||||
# in Kubernetes 1.12 and below.
|
||||
caBundle: ""
|
||||
{{- end }}
|
||||
service:
|
||||
name: {{ template "webhook.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
{{- $isV1AdmissionRegistration := false -}}
|
||||
{{- if (or (not (.Capabilities.APIVersions.Has "admissionregistration.k8s.io/v1")) (.Capabilities.APIVersions.Has "hacking-helm.i-wish-this-wasnt-required.cert-manager.io/force-v1beta1-webhooks") ) }}
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
{{- else }}
|
||||
{{- $isV1AdmissionRegistration = true -}}
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
{{- end }}
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: {{ include "webhook.fullname" . }}
|
||||
@@ -43,21 +37,11 @@ webhooks:
|
||||
- UPDATE
|
||||
resources:
|
||||
- "*/*"
|
||||
{{- if $isV1AdmissionRegistration }}
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
timeoutSeconds: {{ .Values.webhook.timeoutSeconds }}
|
||||
{{- end }}
|
||||
failurePolicy: Fail
|
||||
{{- if (semverCompare ">=1.12-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
# Only include 'sideEffects' field in Kubernetes 1.12+
|
||||
sideEffects: None
|
||||
{{- end }}
|
||||
clientConfig:
|
||||
{{- if (semverCompare "<=1.12-0" .Capabilities.KubeVersion.GitVersion) }}
|
||||
# Set caBundle to empty to avoid https://github.com/kubernetes/kubernetes/pull/70138
|
||||
# in Kubernetes 1.12 and below.
|
||||
caBundle: ""
|
||||
{{- end }}
|
||||
service:
|
||||
name: {{ template "webhook.fullname" . }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
|
||||
@@ -24,6 +24,21 @@ global:
|
||||
# Override the namespace used to store the ConfigMap for leader election
|
||||
namespace: "kube-system"
|
||||
|
||||
# The duration that non-leader candidates will wait after observing a
|
||||
# leadership renewal until attempting to acquire leadership of a led but
|
||||
# unrenewed leader slot. This is effectively the maximum duration that a
|
||||
# leader can be stopped before it is replaced by another candidate.
|
||||
# leaseDuration: 60s
|
||||
|
||||
# The interval between attempts by the acting master to renew a leadership
|
||||
# slot before it stops leading. This must be less than or equal to the
|
||||
# lease duration.
|
||||
# renewDeadline: 40s
|
||||
|
||||
# The duration the clients should wait between attempting acquisition and
|
||||
# renewal of a leadership.
|
||||
# retryPeriod: 15s
|
||||
|
||||
installCRDs: false
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
charts:
|
||||
- name: cert-manager
|
||||
version: v1.1.1
|
||||
version: v1.2.0
|
||||
repo_name: jetstack
|
||||
- name: external-dns
|
||||
repo_name: bitnami
|
||||
|
||||
@@ -795,6 +795,7 @@ datasources:
|
||||
name: "cert-manager-configs".to_string(),
|
||||
path: chart_path("common/charts/cert-manager-configs"),
|
||||
namespace: HelmChartNamespaces::CertManager,
|
||||
backup_resources: Some(vec!["cert".to_string(), "issuer".to_string(), "clusterissuer".to_string()]),
|
||||
values: vec![
|
||||
ChartSetValue {
|
||||
key: "externalDnsProvider".to_string(),
|
||||
|
||||
@@ -611,6 +611,7 @@ datasources:
|
||||
name: "cert-manager-configs".to_string(),
|
||||
path: chart_path("common/charts/cert-manager-configs"),
|
||||
namespace: HelmChartNamespaces::CertManager,
|
||||
backup_resources: Some(vec!["cert".to_string(), "issuer".to_string(), "clusterissuer".to_string()]),
|
||||
values: vec![
|
||||
ChartSetValue {
|
||||
key: "externalDnsProvider".to_string(),
|
||||
|
||||
@@ -2,6 +2,9 @@ use crate::cloud_provider::helm::HelmAction::Deploy;
|
||||
use crate::cloud_provider::helm::HelmChartNamespaces::KubeSystem;
|
||||
use crate::cloud_provider::qovery::{get_qovery_app_version, EngineLocation, QoveryAppName, QoveryShellAgent};
|
||||
use crate::cmd::helm::{to_command_error, Helm};
|
||||
use crate::cmd::helm_utils::{
|
||||
apply_chart_backup, delete_unused_chart_backup, prepare_chart_backup_on_upgrade, BackupStatus,
|
||||
};
|
||||
use crate::cmd::kubectl::{
|
||||
kubectl_delete_crash_looping_pods, kubectl_exec_delete_crd, kubectl_exec_get_configmap, kubectl_exec_get_events,
|
||||
kubectl_exec_rollout_restart_deployment, kubectl_exec_with_output,
|
||||
@@ -12,7 +15,7 @@ use crate::utilities::calculate_hash;
|
||||
use semver::Version;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, thread};
|
||||
use thread::spawn;
|
||||
use tracing::{span, Level};
|
||||
@@ -82,6 +85,7 @@ pub struct ChartInfo {
|
||||
pub yaml_files_content: Vec<ChartValuesGenerated>,
|
||||
pub parse_stderr_for_error: bool,
|
||||
pub k8s_selector: Option<String>,
|
||||
pub backup_resources: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl ChartInfo {
|
||||
@@ -146,6 +150,7 @@ impl Default for ChartInfo {
|
||||
yaml_files_content: vec![],
|
||||
parse_stderr_for_error: true,
|
||||
k8s_selector: None,
|
||||
backup_resources: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +237,61 @@ pub trait HelmChart: Send {
|
||||
);
|
||||
}
|
||||
|
||||
helm.upgrade(chart_info, &[]).map_err(to_command_error)?;
|
||||
let installed_version = match helm.get_chart_version(
|
||||
chart_info.name.clone(),
|
||||
Some(chart_info.get_namespace_string().as_str()),
|
||||
environment_variables.as_slice(),
|
||||
) {
|
||||
Ok(version) => version,
|
||||
Err(e) => {
|
||||
warn!("error while trying to get installed version: {:?}", e);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let upgrade_status = match prepare_chart_backup_on_upgrade(
|
||||
kubernetes_config,
|
||||
chart_info.clone(),
|
||||
environment_variables.as_slice(),
|
||||
installed_version,
|
||||
) {
|
||||
Ok(status) => status,
|
||||
Err(e) => {
|
||||
warn!("error while trying to prepare backup: {:?}", e);
|
||||
BackupStatus {
|
||||
is_backupable: false,
|
||||
backup_path: PathBuf::new(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match helm.upgrade(chart_info, &[]).map_err(to_command_error) {
|
||||
Ok(_) => {
|
||||
if upgrade_status.is_backupable {
|
||||
if let Err(e) = apply_chart_backup(
|
||||
kubernetes_config,
|
||||
upgrade_status.backup_path.as_path(),
|
||||
environment_variables.as_slice(),
|
||||
chart_info,
|
||||
) {
|
||||
warn!("error while trying to apply backup: {:?}", e);
|
||||
};
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if upgrade_status.is_backupable {
|
||||
if let Err(e) = delete_unused_chart_backup(
|
||||
kubernetes_config,
|
||||
environment_variables.as_slice(),
|
||||
chart_info,
|
||||
) {
|
||||
warn!("error while trying to delete backup: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
HelmAction::Destroy => {
|
||||
let chart_info = self.get_chart_info();
|
||||
@@ -358,7 +417,7 @@ pub fn deploy_charts_levels(
|
||||
// Common charts
|
||||
//
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct CommonChart {
|
||||
pub chart_info: ChartInfo,
|
||||
}
|
||||
|
||||
@@ -560,6 +560,7 @@ datasources:
|
||||
name: "cert-manager-configs".to_string(),
|
||||
path: chart_path("common/charts/cert-manager-configs"),
|
||||
namespace: HelmChartNamespaces::CertManager,
|
||||
backup_resources: Some(vec!["cert".to_string(), "issuer".to_string(), "clusterissuer".to_string()]),
|
||||
values: vec![
|
||||
ChartSetValue {
|
||||
key: "externalDnsProvider".to_string(),
|
||||
|
||||
202
src/cmd/helm.rs
202
src/cmd/helm.rs
@@ -504,40 +504,38 @@ impl Helm {
|
||||
},
|
||||
);
|
||||
|
||||
match helm_ret {
|
||||
// Ok is ok
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => {
|
||||
error!("Helm error: {:?}", err);
|
||||
if let Err(err) = helm_ret {
|
||||
error!("Helm error: {:?}", err);
|
||||
|
||||
// Try do define/specify a bit more the message
|
||||
let stderr_msg: String = error_message.into_iter().collect();
|
||||
let stderr_msg = format!(
|
||||
"{}: {}",
|
||||
stderr_msg,
|
||||
err.message(ErrorMessageVerbosity::FullDetailsWithoutEnvVars)
|
||||
);
|
||||
let error = if stderr_msg.contains("another operation (install/upgrade/rollback) is in progress") {
|
||||
HelmError::ReleaseLocked(chart.name.clone())
|
||||
} else if stderr_msg.contains("has been rolled back") {
|
||||
HelmError::Rollbacked(chart.name.clone(), UPGRADE)
|
||||
} else if stderr_msg.contains("timed out waiting") {
|
||||
HelmError::Timeout(chart.name.clone(), UPGRADE, stderr_msg)
|
||||
} else {
|
||||
CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
"Helm error".to_string(),
|
||||
Some(stderr_msg),
|
||||
Some(envs.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()),
|
||||
),
|
||||
)
|
||||
};
|
||||
// Try do define/specify a bit more the message
|
||||
let stderr_msg: String = error_message.into_iter().collect();
|
||||
let stderr_msg = format!(
|
||||
"{}: {}",
|
||||
stderr_msg,
|
||||
err.message(ErrorMessageVerbosity::FullDetailsWithoutEnvVars)
|
||||
);
|
||||
let error = if stderr_msg.contains("another operation (install/upgrade/rollback) is in progress") {
|
||||
HelmError::ReleaseLocked(chart.name.clone())
|
||||
} else if stderr_msg.contains("has been rolled back") {
|
||||
HelmError::Rollbacked(chart.name.clone(), UPGRADE)
|
||||
} else if stderr_msg.contains("timed out waiting") {
|
||||
HelmError::Timeout(chart.name.clone(), UPGRADE, stderr_msg)
|
||||
} else {
|
||||
CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
"Helm error".to_string(),
|
||||
Some(stderr_msg),
|
||||
Some(envs.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
return Err(error);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn uninstall_chart_if_breaking_version(
|
||||
@@ -612,17 +610,19 @@ mod tests {
|
||||
|
||||
struct HelmTestCtx {
|
||||
helm: Helm,
|
||||
chart: ChartInfo,
|
||||
charts: Vec<ChartInfo>,
|
||||
}
|
||||
|
||||
impl HelmTestCtx {
|
||||
fn cleanup(&self) {
|
||||
let ret = self.helm.uninstall(&self.chart, &[]);
|
||||
assert!(ret.is_ok())
|
||||
for chart in &self.charts {
|
||||
let ret = self.helm.uninstall(chart, &vec![]);
|
||||
assert!(ret.is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
fn new(release_name: &str) -> HelmTestCtx {
|
||||
let chart = ChartInfo::new_from_custom_namespace(
|
||||
let charts = vec![ChartInfo::new_from_custom_namespace(
|
||||
release_name.to_string(),
|
||||
"tests/helm/simple_nginx".to_string(),
|
||||
"default".to_string(),
|
||||
@@ -630,12 +630,12 @@ mod tests {
|
||||
vec![],
|
||||
false,
|
||||
None,
|
||||
);
|
||||
)];
|
||||
let mut kube_config = dirs::home_dir().unwrap();
|
||||
kube_config.push(".kube/config");
|
||||
let helm = Helm::new(kube_config.to_str().unwrap(), &[]).unwrap();
|
||||
let helm = Helm::new(kube_config.to_str().unwrap(), &vec![]).unwrap();
|
||||
|
||||
let cleanup = HelmTestCtx { helm, chart };
|
||||
let cleanup = HelmTestCtx { helm, charts };
|
||||
cleanup.cleanup();
|
||||
cleanup
|
||||
}
|
||||
@@ -656,26 +656,26 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_release_exist() {
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-release-exist");
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-release-exist");
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name))
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_release() {
|
||||
let HelmTestCtx {
|
||||
ref helm,
|
||||
ref mut chart,
|
||||
ref mut charts,
|
||||
} = HelmTestCtx::new("test-list-release");
|
||||
chart.custom_namespace = Some("hello-my-friend-this-is-a-test".to_string());
|
||||
charts[0].custom_namespace = Some("hello-my-friend-this-is-a-test".to_string());
|
||||
|
||||
// no existing namespace should return an empty array
|
||||
let ret = helm.list_release(Some("tsdfsfsdf"), &[]);
|
||||
assert!(matches!(ret, Ok(vec) if vec.is_empty()));
|
||||
|
||||
// install something
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// We should have at least one release in all the release
|
||||
@@ -683,69 +683,69 @@ mod tests {
|
||||
assert!(matches!(ret, Ok(vec) if !vec.is_empty()));
|
||||
|
||||
// We should have at least one release in all the release
|
||||
let ret = helm.list_release(Some(&chart.get_namespace_string()), &[]);
|
||||
let ret = helm.list_release(Some(&charts[0].get_namespace_string()), &vec![]);
|
||||
assert!(matches!(ret, Ok(vec) if vec.len() == 1));
|
||||
|
||||
// Install a second stuff
|
||||
let HelmTestCtx {
|
||||
ref helm,
|
||||
ref mut chart,
|
||||
ref mut charts,
|
||||
} = HelmTestCtx::new("test-list-release-2");
|
||||
chart.custom_namespace = Some("hello-my-friend-this-is-a-test".to_string());
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
charts[0].custom_namespace = Some("hello-my-friend-this-is-a-test".to_string());
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
let ret = helm.list_release(Some(&chart.get_namespace_string()), &[]);
|
||||
let ret = helm.list_release(Some(&charts[0].get_namespace_string()), &vec![]);
|
||||
assert!(matches!(ret, Ok(vec) if vec.len() == 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upgrade_diff() {
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-upgrade-diff");
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-upgrade-diff");
|
||||
|
||||
let ret = helm.upgrade_diff(chart, &[]);
|
||||
let ret = helm.upgrade_diff(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rollback() {
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-rollback");
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-rollback");
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.rollback(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.rollback(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// install it
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// First revision cannot be rollback
|
||||
let ret = helm.rollback(chart, &[]);
|
||||
let ret = helm.rollback(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::CannotRollback(_))));
|
||||
|
||||
// 2nd upgrade
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// Rollback should be ok now
|
||||
let ret = helm.rollback(chart, &[]);
|
||||
let ret = helm.rollback(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upgrade() {
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-upgrade");
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-upgrade");
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// install it
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// check now it exists
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(_)));
|
||||
}
|
||||
|
||||
@@ -753,37 +753,37 @@ mod tests {
|
||||
fn test_upgrade_timeout() {
|
||||
let HelmTestCtx {
|
||||
ref helm,
|
||||
ref mut chart,
|
||||
ref mut charts,
|
||||
} = HelmTestCtx::new("test-upgrade-timeout");
|
||||
chart.timeout_in_seconds = 1;
|
||||
charts[0].timeout_in_seconds = 1;
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// install it
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::Timeout(_, _, _))));
|
||||
|
||||
// Release should not exist if it fails
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upgrade_with_lock_during_install() {
|
||||
// We want to check that we manage to install a chart even if a lock is present while it was the first installation
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-upgrade-with-lock-install");
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-upgrade-with-lock-install");
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// Spawn our task killer
|
||||
let barrier = Arc::new(Barrier::new(2));
|
||||
std::thread::spawn({
|
||||
let barrier = barrier.clone();
|
||||
let chart_name = chart.name.clone();
|
||||
let chart_name = charts[0].name.clone();
|
||||
move || {
|
||||
barrier.wait();
|
||||
thread::sleep(Duration::from_millis(3000));
|
||||
@@ -794,19 +794,19 @@ mod tests {
|
||||
|
||||
// install it
|
||||
barrier.wait();
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(_)));
|
||||
|
||||
// Release should be locked
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(release) if release.is_locked()));
|
||||
|
||||
// New installation should work even if a lock is present
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// Release should not be locked anymore
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(release) if !release.is_locked()));
|
||||
}
|
||||
|
||||
@@ -815,22 +815,22 @@ mod tests {
|
||||
// We want to check that we manage to install a chart even if a lock is present while it not the first installation
|
||||
let HelmTestCtx {
|
||||
ref helm,
|
||||
ref mut chart,
|
||||
ref mut charts,
|
||||
} = HelmTestCtx::new("test-upgrade-with-lock-upgrade");
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// First install
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// Spawn our task killer
|
||||
let barrier = Arc::new(Barrier::new(2));
|
||||
std::thread::spawn({
|
||||
let barrier = barrier.clone();
|
||||
let chart_name = chart.name.clone();
|
||||
let chart_name = charts[0].name.clone();
|
||||
move || {
|
||||
barrier.wait();
|
||||
thread::sleep(Duration::from_millis(3000));
|
||||
@@ -839,64 +839,64 @@ mod tests {
|
||||
}
|
||||
});
|
||||
|
||||
chart.values = vec![ChartSetValue {
|
||||
charts[0].values = vec![ChartSetValue {
|
||||
key: "initialDelaySeconds".to_string(),
|
||||
value: "6".to_string(),
|
||||
}];
|
||||
barrier.wait();
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(_)));
|
||||
|
||||
// Release should be locked
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(release) if release.is_locked() && release.version == 2));
|
||||
|
||||
// New installation should work even if a lock is present
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// Release should not be locked anymore
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(release) if !release.is_locked() && release.version == 4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_uninstall() {
|
||||
let HelmTestCtx { ref helm, ref chart } = HelmTestCtx::new("test-uninstall");
|
||||
let HelmTestCtx { ref helm, ref charts } = HelmTestCtx::new("test-uninstall");
|
||||
|
||||
// check release does not exist yet
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
|
||||
// deleting something that does not exist should not be an issue
|
||||
let ret = helm.uninstall(chart, &[]);
|
||||
let ret = helm.uninstall(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// install it
|
||||
let ret = helm.upgrade(chart, &[]);
|
||||
let ret = helm.upgrade(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// check now it exists
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(_)));
|
||||
|
||||
// Delete it
|
||||
let ret = helm.uninstall(chart, &[]);
|
||||
let ret = helm.uninstall(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Ok(())));
|
||||
|
||||
// check release does not exist anymore
|
||||
let ret = helm.check_release_exist(chart, &[]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == chart.name));
|
||||
let ret = helm.check_release_exist(&charts[0], &vec![]);
|
||||
assert!(matches!(ret, Err(HelmError::ReleaseDoesNotExist(test)) if test == charts[0].name));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_getting_version() {
|
||||
let HelmTestCtx {
|
||||
ref helm,
|
||||
ref mut chart,
|
||||
ref mut charts,
|
||||
} = HelmTestCtx::new("test-version-release");
|
||||
let _ = helm.upgrade(chart, &[]);
|
||||
let releases = helm.list_release(Some(&chart.get_namespace_string()), &[]).unwrap();
|
||||
let _ = helm.upgrade(&charts[0], &[]);
|
||||
let releases = helm.list_release(Some(&charts[0].get_namespace_string()), &[]).unwrap();
|
||||
assert_eq!(releases[0].clone().version.unwrap(), Version::new(0, 1, 0))
|
||||
}
|
||||
}
|
||||
|
||||
411
src/cmd/helm_utils.rs
Normal file
411
src/cmd/helm_utils.rs
Normal file
@@ -0,0 +1,411 @@
|
||||
use crate::cloud_provider::helm::ChartInfo;
|
||||
use crate::cmd::helm::HelmError::CmdError;
|
||||
use crate::cmd::helm::{HelmCommand, HelmError};
|
||||
use crate::cmd::kubectl::{
|
||||
kubectl_apply_with_path, kubectl_create_secret_from_file, kubectl_delete_secret, kubectl_exec_get_secrets,
|
||||
kubectl_get_resource_yaml,
|
||||
};
|
||||
use crate::errors::CommandError;
|
||||
use crate::fs::{
|
||||
create_yaml_backup_file, create_yaml_file_from_secret, indent_file, remove_lines_starting_with,
|
||||
truncate_file_from_word,
|
||||
};
|
||||
use semver::Version;
|
||||
use serde_derive::Deserialize;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
pub struct Backup {
|
||||
pub name: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
pub struct BackupInfos {
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChartYAML {
|
||||
#[serde(default)]
|
||||
pub version: String,
|
||||
#[serde(default)]
|
||||
pub app_version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Default)]
|
||||
pub struct BackupStatus {
|
||||
pub is_backupable: bool,
|
||||
pub backup_path: PathBuf,
|
||||
}
|
||||
|
||||
pub fn prepare_chart_backup<P, T>(
|
||||
kubernetes_config: P,
|
||||
workspace_root_dir: T,
|
||||
chart: &ChartInfo,
|
||||
envs: &[(&str, &str)],
|
||||
backup_resources: Vec<String>,
|
||||
) -> Result<Vec<BackupInfos>, HelmError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
T: AsRef<Path>,
|
||||
{
|
||||
let mut backups: Vec<Backup> = vec![];
|
||||
for backup_resource in backup_resources {
|
||||
match kubectl_get_resource_yaml(
|
||||
&kubernetes_config,
|
||||
envs.to_vec(),
|
||||
backup_resource.as_str(),
|
||||
Some(chart.get_namespace_string().as_str()),
|
||||
) {
|
||||
Ok(content) => {
|
||||
if !content.to_lowercase().contains("no resources found") {
|
||||
backups.push(Backup {
|
||||
name: backup_resource,
|
||||
content,
|
||||
});
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Kubectl error: {:?}", e.message_safe())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut backup_infos: Vec<BackupInfos> = vec![];
|
||||
|
||||
if backups.is_empty() {
|
||||
return Ok(backup_infos);
|
||||
}
|
||||
|
||||
for backup in backups.clone() {
|
||||
if !backup.content.is_empty() && !backup.content.contains("items: []") {
|
||||
match create_yaml_backup_file(
|
||||
workspace_root_dir.as_ref(),
|
||||
chart.name.to_string(),
|
||||
Some(backup.name.clone()),
|
||||
backup.content,
|
||||
) {
|
||||
Ok(path) => {
|
||||
backup_infos.push(BackupInfos {
|
||||
name: backup.name,
|
||||
path,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Error while creating YAML backup file for {}.", backup.name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for backup_info in backup_infos.clone() {
|
||||
if let Err(e) = remove_lines_starting_with(
|
||||
backup_info.path.clone(),
|
||||
vec!["resourceVersion", "uid", "apiVersion: v1", "items", "kind: List"],
|
||||
) {
|
||||
return Err(CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Error while editing YAML backup file {}.", backup_info.name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if let Err(e) = truncate_file_from_word(backup_info.path.clone(), "metadata") {
|
||||
return Err(CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Error while editing YAML backup file {}.", backup_info.name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if let Err(e) = indent_file(backup_info.path.clone()) {
|
||||
return Err(CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Error while editing YAML backup file {}.", backup_info.name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let backup_name = format!("{}-{}-q-backup", chart.name, backup_info.name);
|
||||
if let Err(e) = kubectl_create_secret_from_file(
|
||||
&kubernetes_config,
|
||||
envs.to_vec(),
|
||||
Some(chart.namespace.to_string().as_str()),
|
||||
backup_name,
|
||||
backup_info.name,
|
||||
backup_info.path,
|
||||
) {
|
||||
return Err(CmdError(
|
||||
chart.name.clone(),
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(backup_infos)
|
||||
}
|
||||
|
||||
pub fn apply_chart_backup<P>(
|
||||
kubernetes_config: P,
|
||||
workspace_root_dir: P,
|
||||
envs: &[(&str, &str)],
|
||||
chart: &ChartInfo,
|
||||
) -> Result<(), HelmError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let secrets = kubectl_exec_get_secrets(
|
||||
&kubernetes_config,
|
||||
chart.clone().namespace.to_string().as_str(),
|
||||
"",
|
||||
envs.to_vec(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
)
|
||||
})?
|
||||
.items;
|
||||
|
||||
for secret in secrets {
|
||||
if secret.metadata.name.contains("-q-backup") {
|
||||
let path = match create_yaml_file_from_secret(&workspace_root_dir, secret.clone()) {
|
||||
Ok(path) => path,
|
||||
Err(e) => match e.message_safe().to_lowercase().contains("no content") {
|
||||
true => match kubectl_delete_secret(
|
||||
&kubernetes_config,
|
||||
envs.to_vec(),
|
||||
Some(chart.clone().namespace.to_string().as_str()),
|
||||
secret.metadata.name,
|
||||
) {
|
||||
Ok(_) => continue,
|
||||
Err(e) => {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
))
|
||||
}
|
||||
},
|
||||
false => {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(e) = kubectl_apply_with_path(&kubernetes_config, envs.to_vec(), path.as_str()) {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
));
|
||||
};
|
||||
|
||||
if let Err(e) = kubectl_delete_secret(
|
||||
&kubernetes_config,
|
||||
envs.to_vec(),
|
||||
Some(chart.clone().namespace.to_string().as_str()),
|
||||
secret.metadata.name,
|
||||
) {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_unused_chart_backup<P>(
|
||||
kubernetes_config: P,
|
||||
envs: &[(&str, &str)],
|
||||
chart: &ChartInfo,
|
||||
) -> Result<(), HelmError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let secrets = kubectl_exec_get_secrets(
|
||||
&kubernetes_config,
|
||||
chart.clone().namespace.to_string().as_str(),
|
||||
"",
|
||||
envs.to_vec(),
|
||||
)
|
||||
.map_err(|e| {
|
||||
CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
)
|
||||
})?
|
||||
.items;
|
||||
|
||||
for secret in secrets {
|
||||
if secret.metadata.name.contains("-q-backup") {
|
||||
if let Err(e) = kubectl_delete_secret(
|
||||
&kubernetes_config,
|
||||
envs.to_vec(),
|
||||
Some(chart.clone().namespace.to_string().as_str()),
|
||||
secret.metadata.name,
|
||||
) {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(e.message_safe(), e.message_raw(), None),
|
||||
));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_common_helm_chart_infos(chart: &ChartInfo) -> Result<ChartYAML, HelmError> {
|
||||
let string_path = format!("{}/Chart.yaml", chart.path);
|
||||
let file = OpenOptions::new().read(true).open(string_path.as_str()).map_err(|e| {
|
||||
CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Unable to get chart infos for {}.", chart.name.clone()),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let mut content = String::new();
|
||||
let _ = BufReader::new(file).read_to_string(&mut content);
|
||||
match serde_yaml::from_str::<ChartYAML>(content.as_str()) {
|
||||
Ok(chart_yaml) => Ok(chart_yaml),
|
||||
Err(e) => Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Unable to get chart infos for {}.", chart.name.clone()),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_common_helm_chart_version(chart: &ChartInfo) -> Result<Option<Version>, HelmError> {
|
||||
let chart_yaml = match get_common_helm_chart_infos(chart) {
|
||||
Ok(chart_yaml) => chart_yaml,
|
||||
Err(e) => {
|
||||
return Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Unable to get chart version for {}.", chart.name.clone()),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if !chart_yaml.app_version.is_empty() {
|
||||
return match Version::parse(chart_yaml.app_version.as_str()) {
|
||||
Ok(version) => Ok(Some(version)),
|
||||
Err(e) => Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Unable to get chart version for {}.", chart.name.clone()),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
if !chart_yaml.version.is_empty() {
|
||||
return match Version::parse(chart_yaml.version.as_str()) {
|
||||
Ok(version) => Ok(Some(version)),
|
||||
Err(e) => Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new(
|
||||
format!("Unable to get chart version for {}.", chart.name.clone()),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
),
|
||||
)),
|
||||
};
|
||||
}
|
||||
|
||||
Err(CmdError(
|
||||
chart.clone().name,
|
||||
HelmCommand::UPGRADE,
|
||||
CommandError::new_from_safe_message(format!("Unable to get chart version for {}.", chart.name.clone())),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn prepare_chart_backup_on_upgrade<P>(
|
||||
kubernetes_config: P,
|
||||
chart: ChartInfo,
|
||||
envs: &[(&str, &str)],
|
||||
installed_version: Option<Version>,
|
||||
) -> Result<BackupStatus, HelmError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut need_backup = false;
|
||||
let root_dir_path = std::env::temp_dir();
|
||||
|
||||
if chart.backup_resources.is_some() {
|
||||
if installed_version.le(&get_common_helm_chart_version(&chart)?) {
|
||||
if let Err(e) = prepare_chart_backup(
|
||||
kubernetes_config,
|
||||
root_dir_path.as_path(),
|
||||
&chart,
|
||||
envs,
|
||||
chart.backup_resources.as_ref().unwrap().to_vec(),
|
||||
) {
|
||||
return Err(e);
|
||||
};
|
||||
|
||||
need_backup = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BackupStatus {
|
||||
is_backupable: need_backup,
|
||||
backup_path: root_dir_path,
|
||||
})
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
|
||||
use retry::delay::Fibonacci;
|
||||
@@ -1204,6 +1207,30 @@ where
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn kubectl_exec_raw_output<P>(
|
||||
args: Vec<&str>,
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
keep_format: bool,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut _envs = Vec::with_capacity(envs.len() + 1);
|
||||
_envs.push((KUBECONFIG, kubernetes_config.as_ref().to_str().unwrap()));
|
||||
_envs.extend(envs);
|
||||
|
||||
let mut output_vec: Vec<String> = Vec::with_capacity(50);
|
||||
let _ = kubectl_exec_with_output(args.clone(), _envs.clone(), &mut |line| output_vec.push(line), &mut |line| {
|
||||
error!("{}", line)
|
||||
})?;
|
||||
|
||||
match keep_format {
|
||||
true => Ok(output_vec.join("\n")),
|
||||
false => Ok(output_vec.join("")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kubernetes_get_all_pdbs<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
@@ -1245,3 +1272,98 @@ where
|
||||
|
||||
kubectl_exec::<P, HPA>(cmd_args, kubernetes_config, envs)
|
||||
}
|
||||
|
||||
pub fn kubectl_get_resource_yaml<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
resource: &str,
|
||||
namespace: Option<&str>,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut cmd_args = vec!["get", resource, "-oyaml"];
|
||||
match namespace {
|
||||
Some(n) => {
|
||||
cmd_args.push("-n");
|
||||
cmd_args.push(n);
|
||||
}
|
||||
None => cmd_args.push("--all-namespaces"),
|
||||
}
|
||||
|
||||
kubectl_exec_raw_output(cmd_args, kubernetes_config, envs, true)
|
||||
}
|
||||
|
||||
pub fn kubectl_apply_with_path<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
file_path: &str,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
kubectl_exec_raw_output::<P>(vec!["apply", "-f", file_path], kubernetes_config, envs, false)
|
||||
}
|
||||
|
||||
pub fn kubectl_create_secret<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
namespace: Option<&str>,
|
||||
secret_name: String,
|
||||
key: String,
|
||||
value: String,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let secret_arg = format!("--from-literal={}=\"{}\"", key, value);
|
||||
let mut cmd_args = vec!["create", "secret", "generic", secret_name.as_str(), secret_arg.as_str()];
|
||||
match namespace {
|
||||
Some(n) => {
|
||||
cmd_args.push("-n");
|
||||
cmd_args.push(n);
|
||||
}
|
||||
None => cmd_args.push("--all-namespaces"),
|
||||
}
|
||||
|
||||
kubectl_exec_raw_output(cmd_args, kubernetes_config, envs, false)
|
||||
}
|
||||
|
||||
pub fn kubectl_delete_secret<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
namespace: Option<&str>,
|
||||
secret_name: String,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut cmd_args = vec!["delete", "secret", secret_name.as_str()];
|
||||
match namespace {
|
||||
Some(n) => {
|
||||
cmd_args.push("-n");
|
||||
cmd_args.push(n);
|
||||
}
|
||||
None => cmd_args.push("--all-namespaces"),
|
||||
}
|
||||
|
||||
kubectl_exec_raw_output(cmd_args, kubernetes_config, envs, false)
|
||||
}
|
||||
|
||||
pub fn kubectl_create_secret_from_file<P>(
|
||||
kubernetes_config: P,
|
||||
envs: Vec<(&str, &str)>,
|
||||
namespace: Option<&str>,
|
||||
backup_name: String,
|
||||
key: String,
|
||||
file_path: String,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let mut file = File::open(file_path.as_str()).unwrap();
|
||||
let mut content = String::new();
|
||||
let _ = file.read_to_string(&mut content);
|
||||
|
||||
kubectl_create_secret(kubernetes_config, envs, namespace, backup_name, key, content)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod command;
|
||||
pub mod docker;
|
||||
pub mod helm;
|
||||
pub mod helm_utils;
|
||||
pub mod kubectl;
|
||||
pub mod structs;
|
||||
pub mod terraform;
|
||||
|
||||
@@ -42,6 +42,7 @@ pub struct SecretItem {
|
||||
pub api_version: String,
|
||||
pub kind: String,
|
||||
pub metadata: SecretMetadata,
|
||||
pub data: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Deserialize)]
|
||||
|
||||
334
src/fs.rs
334
src/fs.rs
@@ -1,11 +1,16 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::fs::{create_dir_all, File, OpenOptions};
|
||||
use std::io::{BufRead, BufReader, Error, ErrorKind, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::cmd::structs::SecretItem;
|
||||
use crate::errors::CommandError;
|
||||
use base64::decode;
|
||||
use flate2::write::GzEncoder;
|
||||
use flate2::Compression;
|
||||
use itertools::Itertools;
|
||||
use serde::__private::from_utf8_lossy;
|
||||
use std::ffi::OsStr;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
@@ -151,6 +156,232 @@ pub fn create_workspace_archive(working_root_dir: &str, execution_id: &str) -> R
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_yaml_backup_file<P>(
|
||||
working_root_dir: P,
|
||||
chart_name: String,
|
||||
resource_name: Option<String>,
|
||||
content: String,
|
||||
) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let dir = working_root_dir.as_ref().join("backups");
|
||||
|
||||
if let Err(e) = create_dir_all(&dir) {
|
||||
return Err(CommandError::new(
|
||||
"Unable to create root dir path.".to_string(),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
));
|
||||
}
|
||||
|
||||
let root_path = dir
|
||||
.to_str()
|
||||
.map(|e| e.to_string())
|
||||
.ok_or_else(|| CommandError::new_from_safe_message("Unable to get backups root dir path.".to_string()));
|
||||
|
||||
let string_path = match resource_name.is_some() {
|
||||
true => format!(
|
||||
"{}/{}-{}-q-backup.yaml",
|
||||
root_path?,
|
||||
chart_name,
|
||||
resource_name.as_ref().unwrap()
|
||||
),
|
||||
false => format!("{}/{}.yaml", root_path?, chart_name),
|
||||
};
|
||||
let str_path = string_path.as_str();
|
||||
let path = Path::new(str_path);
|
||||
|
||||
let mut file = match File::create(&path) {
|
||||
Err(e) => {
|
||||
return Err(CommandError::new(
|
||||
format!("Unable to create YAML backup file for chart {}.", chart_name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
))
|
||||
}
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
match file.write(content.as_bytes()) {
|
||||
Err(e) => Err(CommandError::new(
|
||||
format!("Unable to edit YAML backup file for chart {}.", chart_name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
)),
|
||||
Ok(_) => Ok(path.to_str().map(|e| e.to_string()).ok_or_else(|| {
|
||||
CommandError::new_from_safe_message(format!(
|
||||
"Unable to get YAML backup file path for chart {}.",
|
||||
chart_name
|
||||
))
|
||||
})?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_lines_starting_with(path: String, starters: Vec<&str>) -> Result<String, CommandError> {
|
||||
let file = OpenOptions::new().read(true).open(path.as_str()).map_err(|e| {
|
||||
CommandError::new(format!("Unable to open YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
let mut content = BufReader::new(file.try_clone().unwrap())
|
||||
.lines()
|
||||
.map(|line| line.unwrap())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
for starter in starters {
|
||||
content = content
|
||||
.into_iter()
|
||||
.filter(|line| !line.contains(starter))
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(path.as_str())
|
||||
.map_err(|e| {
|
||||
CommandError::new(format!("Unable to edit YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
match file.write(content.join("\n").as_bytes()) {
|
||||
Err(e) => Err(CommandError::new(
|
||||
format!("Unable to edit YAML backup file {}.", path),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
)),
|
||||
Ok(_) => Ok(path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn truncate_file_from_word(path: String, truncate_from: &str) -> Result<String, CommandError> {
|
||||
let file = OpenOptions::new().read(true).open(path.as_str()).map_err(|e| {
|
||||
CommandError::new(format!("Unable to open YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
let content_vec = BufReader::new(file.try_clone().unwrap())
|
||||
.lines()
|
||||
.map(|line| line.unwrap())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let truncate_from_index = match content_vec.iter().rposition(|line| line.contains(truncate_from)) {
|
||||
None => content_vec.len(),
|
||||
Some(index) => index,
|
||||
};
|
||||
|
||||
let content = Vec::from(&content_vec[..truncate_from_index]).join("\n");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(path.as_str())
|
||||
.map_err(|e| {
|
||||
CommandError::new(format!("Unable to edit YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
match file.write(content.as_bytes()) {
|
||||
Err(e) => Err(CommandError::new(
|
||||
format!("Unable to edit YAML backup file {}.", path),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
)),
|
||||
Ok(_) => Ok(path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indent_file(path: String) -> Result<String, CommandError> {
|
||||
let file = OpenOptions::new().read(true).open(path.as_str()).map_err(|e| {
|
||||
CommandError::new(format!("Unable to open YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
let file_content = BufReader::new(file.try_clone().unwrap())
|
||||
.lines()
|
||||
.map(|line| line.unwrap())
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
let content = file_content.iter().map(|line| line[2..].to_string()).join("\n");
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(path.as_str())
|
||||
.map_err(|e| {
|
||||
CommandError::new(format!("Unable to edit YAML backup file {}.", path), Some(e.to_string()), None)
|
||||
})?;
|
||||
|
||||
match file.write(content.as_bytes()) {
|
||||
Err(e) => Err(CommandError::new(
|
||||
format!("Unable to edit YAML backup file {}.", path),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
)),
|
||||
Ok(_) => Ok(path),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_yaml_backup_files<P>(working_root_dir: P) -> Result<Vec<String>, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let files = WalkDir::new(working_root_dir)
|
||||
.follow_links(true)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok());
|
||||
let mut backup_paths: Vec<String> = vec![];
|
||||
for file in files {
|
||||
if file
|
||||
.file_name()
|
||||
.to_str()
|
||||
.ok_or_else(|| {
|
||||
CommandError::new_from_safe_message(format!("Unable to get YAML backup file name {:?}.", file))
|
||||
})?
|
||||
.to_string()
|
||||
.contains("-q-backup.yaml")
|
||||
{
|
||||
backup_paths.push(
|
||||
file.path()
|
||||
.to_str()
|
||||
.ok_or_else(|| {
|
||||
CommandError::new_from_safe_message(format!("Unable to get YAML backup file name {:?}.", file))
|
||||
})?
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if backup_paths.is_empty() {
|
||||
return Err(CommandError::new_from_safe_message(
|
||||
"Unable to get YAML backup files".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(backup_paths)
|
||||
}
|
||||
|
||||
pub fn create_yaml_file_from_secret<P>(working_root_dir: P, secret: SecretItem) -> Result<String, CommandError>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let message = format!("Unable to decode secret {}", secret.metadata.name);
|
||||
let secret_data = secret.data.values().next();
|
||||
let secret_content = match secret_data.is_some() {
|
||||
true => secret_data.unwrap().to_string(),
|
||||
false => return Err(CommandError::new_from_safe_message(message)),
|
||||
};
|
||||
|
||||
let content = match decode(secret_content) {
|
||||
Ok(bytes) => from_utf8_lossy(&bytes[1..bytes.len() - 1]).to_string(),
|
||||
Err(e) => return Err(CommandError::new(message, Some(e.to_string()), None)),
|
||||
};
|
||||
match create_yaml_backup_file(working_root_dir.as_ref(), secret.metadata.name.clone(), None, content) {
|
||||
Ok(path) => Ok(path),
|
||||
Err(e) => Err(CommandError::new(
|
||||
format!("Unable to create backup file from secret {}", secret.metadata.name),
|
||||
Some(e.to_string()),
|
||||
None,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tempdir;
|
||||
@@ -159,7 +390,6 @@ mod tests {
|
||||
use flate2::read::GzDecoder;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use tempdir::TempDir;
|
||||
|
||||
@@ -252,4 +482,102 @@ mod tests {
|
||||
tmp_files.into_iter().for_each(drop);
|
||||
tmp_dir.close().expect("error closing temporary directory");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backup_cleaning() {
|
||||
let content = r#"
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
annotations:
|
||||
meta.helm.sh/release-name: cert-manager-configs
|
||||
meta.helm.sh/release-namespace: cert-manager
|
||||
creationTimestamp: "2021-11-04T10:26:27Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: qovery
|
||||
namespace: qovery
|
||||
resourceVersion: "28347460"
|
||||
uid: 509aad5f-db2d-44c3-b03b-beaf144118e2
|
||||
spec:
|
||||
dnsNames:
|
||||
- 'qovery'
|
||||
issuerRef:
|
||||
kind: ClusterIssuer
|
||||
name: qovery
|
||||
secretName: qovery
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2021-11-30T15:33:03Z"
|
||||
message: Certificate is up to date and has not expired
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
notAfter: "2022-04-29T13:34:51Z"
|
||||
notBefore: "2022-01-29T13:34:52Z"
|
||||
renewalTime: "2022-03-30T13:34:51Z"
|
||||
revision: 3
|
||||
"#;
|
||||
|
||||
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
||||
let mut file_path = create_yaml_backup_file(
|
||||
tmp_dir.path().to_str().unwrap(),
|
||||
"test".to_string(),
|
||||
Some("test".to_string()),
|
||||
content.to_string(),
|
||||
)
|
||||
.expect("No such file");
|
||||
file_path = remove_lines_starting_with(file_path, vec!["resourceVersion", "uid"]).unwrap();
|
||||
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(file_path)
|
||||
.expect("file doesn't exist");
|
||||
|
||||
let result = BufReader::new(file.try_clone().unwrap())
|
||||
.lines()
|
||||
.map(|line| line.unwrap())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
|
||||
let new_content = r#"
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
annotations:
|
||||
meta.helm.sh/release-name: cert-manager-configs
|
||||
meta.helm.sh/release-namespace: cert-manager
|
||||
creationTimestamp: "2021-11-04T10:26:27Z"
|
||||
generation: 2
|
||||
labels:
|
||||
app.kubernetes.io/managed-by: Helm
|
||||
name: qovery
|
||||
namespace: qovery
|
||||
spec:
|
||||
dnsNames:
|
||||
- 'qovery'
|
||||
issuerRef:
|
||||
kind: ClusterIssuer
|
||||
name: qovery
|
||||
secretName: qovery
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2021-11-30T15:33:03Z"
|
||||
message: Certificate is up to date and has not expired
|
||||
reason: Ready
|
||||
status: "True"
|
||||
type: Ready
|
||||
notAfter: "2022-04-29T13:34:51Z"
|
||||
notBefore: "2022-01-29T13:34:52Z"
|
||||
renewalTime: "2022-03-30T13:34:51Z"
|
||||
revision: 3
|
||||
"#
|
||||
.to_string();
|
||||
|
||||
assert_eq!(result, new_content);
|
||||
drop(file);
|
||||
tmp_dir.close().expect("error closing temporary directory");
|
||||
}
|
||||
}
|
||||
|
||||
348
tests/helm/cert_manager.rs
Normal file
348
tests/helm/cert_manager.rs
Normal file
@@ -0,0 +1,348 @@
|
||||
use base64::decode;
|
||||
use qovery_engine::cloud_provider::helm::{
|
||||
deploy_charts_levels, ChartInfo, ChartSetValue, CommonChart, HelmChart, HelmChartNamespaces,
|
||||
};
|
||||
use qovery_engine::cmd::helm::Helm;
|
||||
use qovery_engine::cmd::kubectl::{kubectl_exec_delete_namespace, kubectl_exec_get_secrets, kubectl_get_resource_yaml};
|
||||
use qovery_engine::cmd::structs::SecretItem;
|
||||
use qovery_engine::fs::list_yaml_backup_files;
|
||||
use serde_derive::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::from_utf8;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use tempdir::TempDir;
|
||||
use test_utilities::utilities::FuncTestsSecrets;
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Certificate {
|
||||
pub api_version: String,
|
||||
pub items: Vec<Item>,
|
||||
pub kind: String,
|
||||
pub metadata: Metadata2,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Item {
|
||||
pub api_version: String,
|
||||
pub kind: String,
|
||||
pub metadata: Metadata,
|
||||
pub spec: Spec,
|
||||
pub status: Status,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Metadata {
|
||||
pub annotations: Annotations,
|
||||
pub creation_timestamp: String,
|
||||
pub generation: i64,
|
||||
pub labels: Labels,
|
||||
pub name: String,
|
||||
pub namespace: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Annotations {
|
||||
#[serde(rename = "meta.helm.sh/release-name")]
|
||||
pub meta_helm_sh_release_name: String,
|
||||
#[serde(rename = "meta.helm.sh/release-namespace")]
|
||||
pub meta_helm_sh_release_namespace: String,
|
||||
#[serde(default, rename = "kubectl.kubernetes.io/last-applied-configuration")]
|
||||
pub last_applied_configuration: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Labels {
|
||||
#[serde(rename = "app.kubernetes.io/managed-by")]
|
||||
pub app_kubernetes_io_managed_by: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Spec {
|
||||
pub dns_names: Vec<String>,
|
||||
pub issuer_ref: IssuerRef,
|
||||
pub secret_name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct IssuerRef {
|
||||
pub kind: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Status {}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Metadata2 {
|
||||
pub self_link: String,
|
||||
}
|
||||
|
||||
fn cert_manager_conf() -> (Helm, PathBuf, CommonChart, CommonChart) {
|
||||
let vault_secrets = FuncTestsSecrets::new();
|
||||
let mut kube_config = dirs::home_dir().unwrap();
|
||||
kube_config.push(".kube/config");
|
||||
let helm = Helm::new(kube_config.to_str().unwrap(), &[]).unwrap();
|
||||
let cert_manager = CommonChart {
|
||||
chart_info: ChartInfo {
|
||||
name: "cert-manager".to_string(),
|
||||
path: "lib/common/bootstrap/charts/cert-manager".to_string(),
|
||||
namespace: HelmChartNamespaces::CertManager,
|
||||
values: vec![
|
||||
ChartSetValue {
|
||||
key: "installCRDs".to_string(),
|
||||
value: "true".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "replicaCount".to_string(),
|
||||
value: "1".to_string(),
|
||||
},
|
||||
// https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check
|
||||
ChartSetValue {
|
||||
key: "extraArgs".to_string(),
|
||||
value: "{--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=1.1.1.1:53\\,8.8.8.8:53}"
|
||||
.to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "prometheus.servicemonitor.enabled".to_string(),
|
||||
// Due to cycle, prometheus need tls certificate from cert manager, and enabling this will require
|
||||
// prometheus to be already installed
|
||||
value: "false".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "prometheus.servicemonitor.prometheusInstance".to_string(),
|
||||
value: "qovery".to_string(),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
let cert_manager_config = CommonChart {
|
||||
chart_info: ChartInfo {
|
||||
name: "cert-manager-configs".to_string(),
|
||||
path: "lib/common/bootstrap/charts/cert-manager-configs".to_string(),
|
||||
namespace: HelmChartNamespaces::CertManager,
|
||||
values: vec![
|
||||
ChartSetValue {
|
||||
key: "externalDnsProvider".to_string(),
|
||||
value: "cloudflare".to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "provider.cloudflare.apiToken".to_string(),
|
||||
value: vault_secrets.CLOUDFLARE_TOKEN.unwrap().to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "provider.cloudflare.email".to_string(),
|
||||
value: vault_secrets.CLOUDFLARE_ID.as_ref().unwrap().to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "acme.letsEncrypt.emailReport".to_string(),
|
||||
value: vault_secrets.CLOUDFLARE_ID.unwrap().to_string(),
|
||||
},
|
||||
ChartSetValue {
|
||||
key: "acme.letsEncrypt.acmeUrl".to_string(),
|
||||
value: "https://acme-staging-v02.api.letsencrypt.org/directory".to_string(),
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
(helm, kube_config, cert_manager, cert_manager_config)
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-with-kube")]
|
||||
#[test]
|
||||
fn test_create_chart_backup() {
|
||||
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
||||
|
||||
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
||||
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
||||
|
||||
sleep(Duration::from_secs(30));
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
||||
|
||||
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
||||
let root_dir_path = Path::new(tmp_dir.path());
|
||||
let backup_infos = helm
|
||||
.prepare_chart_backup(root_dir_path, &cert_manager.chart_info, &vec![], vec!["cert".to_string()])
|
||||
.unwrap();
|
||||
let secrets = kubectl_exec_get_secrets(
|
||||
kube_config.as_path(),
|
||||
cert_manager.chart_info.namespace.to_string().as_str(),
|
||||
"",
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(backup_infos.len(), 1);
|
||||
|
||||
for backup_info in backup_infos {
|
||||
let backup_name = format!("{}-{}-q-backup", &cert_manager.chart_info.name, backup_info.name.clone());
|
||||
assert!(Path::new(backup_info.path.as_str()).exists());
|
||||
let secret = secrets
|
||||
.items
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|secret| secret.metadata.name == backup_name)
|
||||
.collect::<Vec<SecretItem>>();
|
||||
let secret_content = decode(secret[0].data[&backup_info.name].clone()).unwrap();
|
||||
let content = from_utf8(secret_content.as_slice()).unwrap().to_string();
|
||||
let file = OpenOptions::new().read(true).open(backup_info.path.as_str()).unwrap();
|
||||
let file_content = BufReader::new(file.try_clone().unwrap())
|
||||
.lines()
|
||||
.map(|line| line.unwrap())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
assert_ne!(content.len(), 0);
|
||||
assert_ne!(file_content.len(), 0);
|
||||
assert!(content.contains(&file_content));
|
||||
}
|
||||
|
||||
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-with-kube")]
|
||||
#[test]
|
||||
fn test_apply_chart_backup() {
|
||||
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
||||
|
||||
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
||||
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
||||
|
||||
sleep(Duration::from_secs(30));
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
||||
|
||||
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
||||
let root_dir_path = Path::new(tmp_dir.path());
|
||||
let _ = helm
|
||||
.prepare_chart_backup(
|
||||
root_dir_path,
|
||||
cert_manager_config.get_chart_info(),
|
||||
&vec![],
|
||||
vec!["cert".to_string()],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
match helm.apply_chart_backup(root_dir_path, &vec![], cert_manager_config.get_chart_info()) {
|
||||
Err(_) => {
|
||||
assert!(false)
|
||||
}
|
||||
Ok(..) => {
|
||||
let string_path = list_yaml_backup_files(root_dir_path).unwrap().first().unwrap().clone();
|
||||
let str_path = string_path.as_str();
|
||||
let path = Path::new(str_path);
|
||||
let backup_string = fs::read_to_string(path).unwrap();
|
||||
let cert_string = kubectl_get_resource_yaml(
|
||||
kube_config.as_path(),
|
||||
vec![],
|
||||
"cert",
|
||||
Some(cert_manager_config.namespace().as_str()),
|
||||
)
|
||||
.unwrap();
|
||||
let backup_cert = serde_yaml::from_str::<Certificate>(backup_string.as_str()).unwrap();
|
||||
let cert = serde_yaml::from_str::<Certificate>(cert_string.as_str()).unwrap();
|
||||
assert_eq!(backup_cert.items.first().unwrap().spec, cert.items.first().unwrap().spec)
|
||||
}
|
||||
};
|
||||
|
||||
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-with-kube")]
|
||||
#[test]
|
||||
fn test_should_not_create_chart_backup() {
|
||||
let (helm, kube_config, cert_manager, cert_manager_config) = cert_manager_conf();
|
||||
|
||||
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
||||
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
||||
|
||||
sleep(Duration::from_secs(30));
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
||||
|
||||
let tmp_dir = TempDir::new("workspace_directory").expect("error creating temporary dir");
|
||||
let root_dir_path = Path::new(tmp_dir.path());
|
||||
|
||||
// trying to create a backup from an unknown (toto) resource
|
||||
let backup_infos = helm
|
||||
.prepare_chart_backup(root_dir_path, &cert_manager.chart_info, &vec![], vec!["toto".to_string()])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(backup_infos.len(), 0);
|
||||
|
||||
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-with-kube")]
|
||||
#[test]
|
||||
fn test_should_apply_chart_backup() {
|
||||
let (helm, kube_config, cert_manager, mut cert_manager_config) = cert_manager_conf();
|
||||
|
||||
let lvl_1: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager.clone())];
|
||||
let lvl_2: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_1], false).map_err(|_| assert!(false));
|
||||
|
||||
sleep(Duration::from_secs(30));
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2], false).map_err(|_| assert!(false));
|
||||
|
||||
sleep(Duration::from_secs(30));
|
||||
|
||||
cert_manager_config.chart_info.backup_resources = Some(vec!["cert".to_string()]);
|
||||
|
||||
let lvl_2_bis: Vec<Box<dyn HelmChart>> = vec![Box::new(cert_manager_config.clone())];
|
||||
|
||||
let _ = deploy_charts_levels(kube_config.as_path(), &vec![], vec![lvl_2_bis], false).map_err(|_| assert!(false));
|
||||
|
||||
let secrets = kubectl_exec_get_secrets(
|
||||
kube_config.as_path(),
|
||||
cert_manager.chart_info.namespace.to_string().as_str(),
|
||||
"",
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cert_secret = secrets
|
||||
.items
|
||||
.into_iter()
|
||||
.filter(|secret| secret.metadata.name == "cert-manager-configs-cert-q-backup")
|
||||
.collect::<Vec<SecretItem>>();
|
||||
|
||||
assert_eq!(cert_secret.len(), 0);
|
||||
|
||||
let cert_string = kubectl_get_resource_yaml(
|
||||
kube_config.as_path(),
|
||||
vec![],
|
||||
"cert",
|
||||
Some(cert_manager_config.namespace().as_str()),
|
||||
)
|
||||
.unwrap();
|
||||
let cert = serde_yaml::from_str::<Certificate>(cert_string.as_str()).unwrap();
|
||||
|
||||
assert_ne!(cert.items[0].metadata.annotations.last_applied_configuration, "");
|
||||
|
||||
let _ = kubectl_exec_delete_namespace(kube_config.as_path(), "cert-manager", vec![]);
|
||||
}
|
||||
1
tests/helm/mod.rs
Normal file
1
tests/helm/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod cert_manager;
|
||||
@@ -3,4 +3,5 @@ extern crate maplit;
|
||||
|
||||
mod aws;
|
||||
mod digitalocean;
|
||||
mod helm;
|
||||
mod scaleway;
|
||||
|
||||
Reference in New Issue
Block a user