Merge pull request #7776 from dokku/k3s-kustomize
Add kustomize support for applying helm charts
This commit is contained in:
@@ -141,6 +141,7 @@ The k3s plugin provides a number of settings that can be used to managed deploym
|
|||||||
| Name | Description | Global Default |
|
| Name | Description | Global Default |
|
||||||
|-----------------------|---------------------------------------------------|--------------------|
|
|-----------------------|---------------------------------------------------|--------------------|
|
||||||
| `deploy-timeout` | Controls when app deploys will timeout in seconds | `300s` |
|
| `deploy-timeout` | Controls when app deploys will timeout in seconds | `300s` |
|
||||||
|
| `kustomize-root-path` | Controls the folder context from the deployed repository used for Kustomize | `config/kustomize` |
|
||||||
| `image-pull-secrets` | Name of a kubernetes secret used to auth against a registry | Contents of `~/.docker/config.json` from Dokku server |
|
| `image-pull-secrets` | Name of a kubernetes secret used to auth against a registry | Contents of `~/.docker/config.json` from Dokku server |
|
||||||
| `namespace` | Controls the namespace used for resource creation | `default` |
|
| `namespace` | Controls the namespace used for resource creation | `default` |
|
||||||
| `rollback-on-failure` | Whether to rollback failed deploys | `false` |
|
| `rollback-on-failure` | Whether to rollback failed deploys | `false` |
|
||||||
@@ -365,7 +366,6 @@ dokku scheduler-k3s:ensure-charts
|
|||||||
|
|
||||||
Once the chart is configured, an `http` trigger can be specified like so:
|
Once the chart is configured, an `http` trigger can be specified like so:
|
||||||
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"formation": {
|
"formation": {
|
||||||
@@ -461,6 +461,30 @@ dokku scheduler-k3s:autoscaling-auth:report node-js-app --include-metadata
|
|||||||
Datadog datadogSite: us5.datadoghq.com
|
Datadog datadogSite: us5.datadoghq.com
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Integrating Kustomize
|
||||||
|
|
||||||
|
Dokku supports integration with [Kustomize](https://kustomize.io/) to further customize the generated helm charts for app deployments. For example, a `config/kustomize/kustomization.yaml` file with the following contents will override the scale for each process deployed to `3`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- rendered.yaml
|
||||||
|
patches:
|
||||||
|
- patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/replicas
|
||||||
|
value: 3
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
When using Kustomize with Dokku, all Kustomize-files _must_ be placed in the `config/kustomize` folder, with a `kustomization.yaml` file being the entrypoint to Kustomize. Dokku will render the helm chart to a `rendered.yaml` file, and then execute Kustomize with the `config/kustomize` folder as the context.
|
||||||
|
|
||||||
|
See the [Kustomize](https://kustomize.io/) website for more details on how to use Kustomize.
|
||||||
|
|
||||||
### Using kubectl remotely
|
### Using kubectl remotely
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
@@ -515,7 +539,6 @@ dokku scheduler-k3s:set --global chart.cert-manager.version 1.13.3
|
|||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> Properties follow dot-notation, and are expanded according to Helm's internal logic. See the [Helm documentation](https://helm.sh/docs/helm/helm_install/#helm-install) for `helm install` for further details.
|
> Properties follow dot-notation, and are expanded according to Helm's internal logic. See the [Helm documentation](https://helm.sh/docs/helm/helm_install/#helm-install) for `helm install` for further details.
|
||||||
|
|
||||||
|
|
||||||
To unset a chart property, omit the value from the `scheduler-k3s:set` call:
|
To unset a chart property, omit the value from the `scheduler-k3s:set` call:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
||||||
TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
TRIGGERS = triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
||||||
BUILD = commands subcommands triggers
|
BUILD = commands subcommands triggers
|
||||||
PLUGIN_NAME = scheduler-k3s
|
PLUGIN_NAME = scheduler-k3s
|
||||||
|
|
||||||
|
|||||||
@@ -576,7 +576,7 @@ func getAutoscaling(input GetAutoscalingInput) (ProcessAutoscaling, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
common.LogWarn(fmt.Sprintf("No autoscaling config found for %s", input.AppName))
|
common.LogWarn(fmt.Sprintf("No autoscaling config found for %s:%s", input.AppName, input.ProcessType))
|
||||||
return ProcessAutoscaling{}, nil
|
return ProcessAutoscaling{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1190,6 +1190,28 @@ func getGlobalLetsencryptEmailStag() string {
|
|||||||
return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-email-stag", "")
|
return common.PropertyGetDefault("scheduler-k3s", "--global", "letsencrypt-email-stag", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getKustomizeDirectory(appName string) string {
|
||||||
|
directory := filepath.Join(common.MustGetEnv("DOKKU_LIB_ROOT"), "data", "scheduler-k3s", appName)
|
||||||
|
return filepath.Join(directory, "kustomization")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKustomizeRootPath(appName string) string {
|
||||||
|
return common.PropertyGetDefault("scheduler-k3s", appName, "kustomize-root-path", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGlobalKustomizeRootPath() string {
|
||||||
|
return common.PropertyGetDefault("scheduler-k3s", "--global", "kustomize-root-path", "config/kustomize")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getComputedKustomizeRootPath(appName string) string {
|
||||||
|
kustomizeRootPath := getKustomizeRootPath(appName)
|
||||||
|
if kustomizeRootPath == "" {
|
||||||
|
kustomizeRootPath = getGlobalKustomizeRootPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
return kustomizeRootPath
|
||||||
|
}
|
||||||
|
|
||||||
func getNamespace(appName string) string {
|
func getNamespace(appName string) string {
|
||||||
return common.PropertyGetDefault("scheduler-k3s", appName, "namespace", "")
|
return common.PropertyGetDefault("scheduler-k3s", appName, "namespace", "")
|
||||||
}
|
}
|
||||||
@@ -1477,6 +1499,34 @@ func getStartCommand(input StartCommandInput) (StartCommandOutput, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getProcessSpecificKustomizeRootPath(appName string) string {
|
||||||
|
if !hasKustomizeDirectory(appName) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
directory := getKustomizeDirectory(appName)
|
||||||
|
processSpecificDirectory := fmt.Sprintf("%s.%s", directory, os.Getenv("DOKKU_PID"))
|
||||||
|
if common.DirectoryExists(processSpecificDirectory) {
|
||||||
|
return processSpecificDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasKustomizeDirectory(appName string) bool {
|
||||||
|
directory := getKustomizeDirectory(appName)
|
||||||
|
|
||||||
|
if common.DirectoryExists(fmt.Sprintf("%s.%s.missing", directory, os.Getenv("DOKKU_PID"))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if common.DirectoryExists(fmt.Sprintf("%s.%s", directory, os.Getenv("DOKKU_PID"))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.DirectoryExists(directory)
|
||||||
|
}
|
||||||
|
|
||||||
func installHelmCharts(ctx context.Context, clientset KubernetesClient, shouldInstall func(HelmChart) bool) error {
|
func installHelmCharts(ctx context.Context, clientset KubernetesClient, shouldInstall func(HelmChart) bool) error {
|
||||||
for _, repo := range HelmRepositories {
|
for _, repo := range HelmRepositories {
|
||||||
helmAgent, err := NewHelmAgent("default", DeployLogPrinter)
|
helmAgent, err := NewHelmAgent("default", DeployLogPrinter)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ require (
|
|||||||
github.com/dokku/dokku/plugins/logs v0.0.0-20250618161309-8d0c35f1333c
|
github.com/dokku/dokku/plugins/logs v0.0.0-20250618161309-8d0c35f1333c
|
||||||
github.com/dokku/dokku/plugins/nginx-vhosts v0.0.0-20250618161309-8d0c35f1333c
|
github.com/dokku/dokku/plugins/nginx-vhosts v0.0.0-20250618161309-8d0c35f1333c
|
||||||
github.com/fatih/color v1.18.0
|
github.com/fatih/color v1.18.0
|
||||||
|
github.com/fluxcd/pkg/kustomize v1.18.0
|
||||||
github.com/go-openapi/jsonpointer v0.21.1
|
github.com/go-openapi/jsonpointer v0.21.1
|
||||||
github.com/go-resty/resty/v2 v2.16.5
|
github.com/go-resty/resty/v2 v2.16.5
|
||||||
github.com/gofrs/flock v0.12.1
|
github.com/gofrs/flock v0.12.1
|
||||||
@@ -30,6 +31,7 @@ require (
|
|||||||
k8s.io/kubernetes v1.33.2
|
k8s.io/kubernetes v1.33.2
|
||||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||||
mvdan.cc/sh/v3 v3.12.0
|
mvdan.cc/sh/v3 v3.12.0
|
||||||
|
sigs.k8s.io/kustomize/api v0.20.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -168,7 +170,6 @@ require (
|
|||||||
sigs.k8s.io/controller-runtime v0.21.0 // indirect
|
sigs.k8s.io/controller-runtime v0.21.0 // indirect
|
||||||
sigs.k8s.io/gateway-api v1.3.0 // indirect
|
sigs.k8s.io/gateway-api v1.3.0 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||||
sigs.k8s.io/kustomize/api v0.20.0 // indirect
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect
|
sigs.k8s.io/kustomize/kyaml v0.20.0 // indirect
|
||||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
|||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/fluxcd/pkg/kustomize v1.18.0 h1:wWK+qYwmBmba3N3VAqZ9ijnfVGGaIjcaHWo033URZTw=
|
||||||
|
github.com/fluxcd/pkg/kustomize v1.18.0/go.mod h1:Ij9722MdWIE6B1EPg2ZJUf6npycgfRfN4Lohi7D/Kic=
|
||||||
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
||||||
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/dokku/dokku/plugins/common"
|
"github.com/dokku/dokku/plugins/common"
|
||||||
|
"github.com/fluxcd/pkg/kustomize/filesys"
|
||||||
"github.com/gofrs/flock"
|
"github.com/gofrs/flock"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"helm.sh/helm/v3/pkg/action"
|
"helm.sh/helm/v3/pkg/action"
|
||||||
@@ -21,9 +22,13 @@ import (
|
|||||||
"helm.sh/helm/v3/pkg/cli"
|
"helm.sh/helm/v3/pkg/cli"
|
||||||
"helm.sh/helm/v3/pkg/getter"
|
"helm.sh/helm/v3/pkg/getter"
|
||||||
"helm.sh/helm/v3/pkg/kube"
|
"helm.sh/helm/v3/pkg/kube"
|
||||||
|
"helm.sh/helm/v3/pkg/postrender"
|
||||||
"helm.sh/helm/v3/pkg/release"
|
"helm.sh/helm/v3/pkg/release"
|
||||||
"helm.sh/helm/v3/pkg/repo"
|
"helm.sh/helm/v3/pkg/repo"
|
||||||
"helm.sh/helm/v3/pkg/storage/driver"
|
"helm.sh/helm/v3/pkg/storage/driver"
|
||||||
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
|
"sigs.k8s.io/kustomize/api/krusty"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DevNullPrinter = func(format string, v ...interface{}) {}
|
var DevNullPrinter = func(format string, v ...interface{}) {}
|
||||||
@@ -46,16 +51,37 @@ var DeployLogPrinter = func(format string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChartInput is the input for the InstallOrUpgradeChart function
|
||||||
type ChartInput struct {
|
type ChartInput struct {
|
||||||
ChartPath string
|
// ChartPath is the path to the chart to install or upgrade
|
||||||
Namespace string
|
ChartPath string
|
||||||
ReleaseName string
|
|
||||||
RepoURL string
|
// KustomizeRootPath is the path to the kustomize root path to use
|
||||||
|
KustomizeRootPath string
|
||||||
|
|
||||||
|
// Namespace is the namespace to install or upgrade the chart in
|
||||||
|
Namespace string
|
||||||
|
|
||||||
|
// ReleaseName is the name of the release to install or upgrade
|
||||||
|
ReleaseName string
|
||||||
|
|
||||||
|
// RepoURL is the URL of the chart repository to install or upgrade the chart from
|
||||||
|
RepoURL string
|
||||||
|
|
||||||
|
// RollbackOnFailure is whether to rollback on failure
|
||||||
RollbackOnFailure bool
|
RollbackOnFailure bool
|
||||||
Timeout time.Duration
|
|
||||||
Wait bool
|
// Timeout is the timeout for the install or upgrade
|
||||||
Version string
|
Timeout time.Duration
|
||||||
Values map[string]interface{}
|
|
||||||
|
// Wait is whether to wait for the install or upgrade to complete
|
||||||
|
Wait bool
|
||||||
|
|
||||||
|
// Version is the version of the chart to install or upgrade
|
||||||
|
Version string
|
||||||
|
|
||||||
|
// Values is the values to pass to the chart
|
||||||
|
Values map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Release struct {
|
type Release struct {
|
||||||
@@ -237,11 +263,22 @@ func (h *HelmAgent) InstallChart(ctx context.Context, input ChartInput) error {
|
|||||||
input.Values = map[string]interface{}{}
|
input.Values = map[string]interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kustomizeRenderer := KustomizeRenderer{
|
||||||
|
KustomizeRootPath: input.KustomizeRootPath,
|
||||||
|
}
|
||||||
|
|
||||||
client := action.NewInstall(h.Configuration)
|
client := action.NewInstall(h.Configuration)
|
||||||
client.Atomic = false
|
client.Atomic = false
|
||||||
client.ChartPathOptions = action.ChartPathOptions{}
|
client.ChartPathOptions = action.ChartPathOptions{}
|
||||||
client.CreateNamespace = true
|
client.CreateNamespace = true
|
||||||
client.DryRun = false
|
client.DryRun = false
|
||||||
|
if os.Getenv("DOKKU_TRACE") == "1" {
|
||||||
|
client.PostRenderer = &DebugRenderer{
|
||||||
|
Renderer: &kustomizeRenderer,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
client.PostRenderer = &kustomizeRenderer
|
||||||
|
}
|
||||||
client.Namespace = namespace
|
client.Namespace = namespace
|
||||||
client.ReleaseName = input.ReleaseName
|
client.ReleaseName = input.ReleaseName
|
||||||
client.Timeout = input.Timeout
|
client.Timeout = input.Timeout
|
||||||
@@ -333,16 +370,6 @@ func (h *HelmAgent) ListRevisions(input ListRevisionsInput) ([]Release, error) {
|
|||||||
return releases, nil
|
return releases, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DebugRenderer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *DebugRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
|
|
||||||
for _, line := range strings.Split(renderedManifests.String(), "\n") {
|
|
||||||
common.LogWarn(line)
|
|
||||||
}
|
|
||||||
return renderedManifests, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error {
|
func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error {
|
||||||
namespace := input.Namespace
|
namespace := input.Namespace
|
||||||
if namespace == "" {
|
if namespace == "" {
|
||||||
@@ -359,14 +386,21 @@ func (h *HelmAgent) UpgradeChart(ctx context.Context, input ChartInput) error {
|
|||||||
input.Values = map[string]interface{}{}
|
input.Values = map[string]interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kustomizeRenderer := KustomizeRenderer{
|
||||||
|
KustomizeRootPath: input.KustomizeRootPath,
|
||||||
|
}
|
||||||
|
|
||||||
client := action.NewUpgrade(h.Configuration)
|
client := action.NewUpgrade(h.Configuration)
|
||||||
client.Atomic = input.RollbackOnFailure
|
client.Atomic = input.RollbackOnFailure
|
||||||
client.ChartPathOptions = action.ChartPathOptions{}
|
client.ChartPathOptions = action.ChartPathOptions{}
|
||||||
client.CleanupOnFail = true
|
client.CleanupOnFail = true
|
||||||
client.MaxHistory = 10
|
client.MaxHistory = 10
|
||||||
if os.Getenv("DOKKU_TRACE") == "1" {
|
if os.Getenv("DOKKU_TRACE") == "1" {
|
||||||
client.DryRun = true
|
client.PostRenderer = &DebugRenderer{
|
||||||
client.PostRenderer = &DebugRenderer{}
|
Renderer: &kustomizeRenderer,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
client.PostRenderer = &kustomizeRenderer
|
||||||
}
|
}
|
||||||
client.Namespace = namespace
|
client.Namespace = namespace
|
||||||
client.Timeout = input.Timeout
|
client.Timeout = input.Timeout
|
||||||
@@ -413,3 +447,71 @@ func (h *HelmAgent) UninstallChart(releaseName string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DebugRenderer struct {
|
||||||
|
Renderer postrender.PostRenderer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DebugRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
|
||||||
|
renderedManifests, err := p.Renderer.Run(renderedManifests)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(renderedManifests.String(), "\n") {
|
||||||
|
common.LogWarn(line)
|
||||||
|
}
|
||||||
|
return renderedManifests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type KustomizeRenderer struct {
|
||||||
|
KustomizeRootPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *KustomizeRenderer) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) {
|
||||||
|
if p.KustomizeRootPath == "" {
|
||||||
|
return renderedManifests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !common.DirectoryExists(p.KustomizeRootPath) {
|
||||||
|
return renderedManifests, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, err := filesys.MakeFsOnDiskSecureBuild(p.KustomizeRootPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating filesystem: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var kfile string
|
||||||
|
for _, f := range konfig.RecognizedKustomizationFileNames() {
|
||||||
|
if kf := filepath.Join(p.KustomizeRootPath, f); fs.Exists(kf) {
|
||||||
|
kfile = kf
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if kfile == "" {
|
||||||
|
return nil, fmt.Errorf("%s not found", konfig.DefaultKustomizationFileName())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fs.WriteFile(filepath.Join(p.KustomizeRootPath, "rendered.yaml"), renderedManifests.Bytes()); err != nil {
|
||||||
|
return nil, fmt.Errorf("Error writing rendered.yaml: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buildOptions := &krusty.Options{
|
||||||
|
LoadRestrictions: types.LoadRestrictionsNone,
|
||||||
|
PluginConfig: types.DisabledPluginConfig(),
|
||||||
|
}
|
||||||
|
|
||||||
|
k := krusty.MakeKustomizer(buildOptions)
|
||||||
|
m, err := k.Run(fs, p.KustomizeRootPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resources, err := m.AsYaml()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes.NewBuffer(resources), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -416,6 +416,35 @@ func (k KubernetesClient) ExecCommand(ctx context.Context, input ExecCommandInpu
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPodLogsInput contains all the information needed to get the logs for a Kubernetes pod
|
||||||
|
type GetLogsInput struct {
|
||||||
|
// Name is the Kubernetes pod name
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Namespace is the Kubernetes namespace
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogs gets the logs for a Kubernetes pod
|
||||||
|
func (k KubernetesClient) GetLogs(ctx context.Context, input GetLogsInput) ([]byte, error) {
|
||||||
|
logOptions := corev1.PodLogOptions{}
|
||||||
|
|
||||||
|
request := k.Client.CoreV1().Pods(input.Namespace).GetLogs(input.Name, &logOptions)
|
||||||
|
|
||||||
|
readCloser, err := request.Stream(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get logs: %w", err)
|
||||||
|
}
|
||||||
|
defer readCloser.Close()
|
||||||
|
|
||||||
|
bytes, err := io.ReadAll(readCloser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read logs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetNodeInput contains all the information needed to get a Kubernetes node
|
// GetNodeInput contains all the information needed to get a Kubernetes node
|
||||||
type GetNodeInput struct {
|
type GetNodeInput struct {
|
||||||
// Name is the Kubernetes node name
|
// Name is the Kubernetes node name
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
|
|||||||
"--scheduler-k3s-global-ingress-class": reportGlobalIngressClass,
|
"--scheduler-k3s-global-ingress-class": reportGlobalIngressClass,
|
||||||
"--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd,
|
"--scheduler-k3s-global-letsencrypt-email-prod": reportGlobalLetsencryptEmailProd,
|
||||||
"--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag,
|
"--scheduler-k3s-global-letsencrypt-email-stag": reportGlobalLetsencryptEmailStag,
|
||||||
|
"--scheduler-k3s-computed-kustomize-root-path": reportComputedKustomizeRootPath,
|
||||||
|
"--scheduler-k3s-kustomize-root-path": reportKustomizeRootPath,
|
||||||
|
"--scheduler-k3s-global-kustomize-root-path": reportGlobalKustomizeRootPath,
|
||||||
"--scheduler-k3s-computed-namespace": reportComputedNamespace,
|
"--scheduler-k3s-computed-namespace": reportComputedNamespace,
|
||||||
"--scheduler-k3s-namespace": reportNamespace,
|
"--scheduler-k3s-namespace": reportNamespace,
|
||||||
"--scheduler-k3s-global-namespace": reportGlobalNamespace,
|
"--scheduler-k3s-global-namespace": reportGlobalNamespace,
|
||||||
@@ -148,6 +151,18 @@ func reportGlobalLetsencryptEmailStag(appName string) string {
|
|||||||
return getGlobalLetsencryptEmailStag()
|
return getGlobalLetsencryptEmailStag()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func reportComputedKustomizeRootPath(appName string) string {
|
||||||
|
return getComputedKustomizeRootPath(appName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reportKustomizeRootPath(appName string) string {
|
||||||
|
return getKustomizeRootPath(appName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reportGlobalKustomizeRootPath(appName string) string {
|
||||||
|
return getGlobalKustomizeRootPath()
|
||||||
|
}
|
||||||
|
|
||||||
func reportComputedNamespace(appName string) string {
|
func reportComputedNamespace(appName string) string {
|
||||||
return getComputedNamespace(appName)
|
return getComputedNamespace(appName)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ var (
|
|||||||
DefaultProperties = map[string]string{
|
DefaultProperties = map[string]string{
|
||||||
"deploy-timeout": "",
|
"deploy-timeout": "",
|
||||||
"letsencrypt-server": "",
|
"letsencrypt-server": "",
|
||||||
|
"kustomize-root-path": "",
|
||||||
"image-pull-secrets": "",
|
"image-pull-secrets": "",
|
||||||
"namespace": "",
|
"namespace": "",
|
||||||
"rollback-on-failure": "",
|
"rollback-on-failure": "",
|
||||||
@@ -33,6 +34,7 @@ var (
|
|||||||
"ingress-class": true,
|
"ingress-class": true,
|
||||||
"kube-context": true,
|
"kube-context": true,
|
||||||
"kubeconfig-path": true,
|
"kubeconfig-path": true,
|
||||||
|
"kustomize-root-path": true,
|
||||||
"letsencrypt-server": true,
|
"letsencrypt-server": true,
|
||||||
"letsencrypt-email-prod": true,
|
"letsencrypt-email-prod": true,
|
||||||
"letsencrypt-email-stag": true,
|
"letsencrypt-email-stag": true,
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ func main() {
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch trigger {
|
switch trigger {
|
||||||
|
case "core-post-deploy":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
err = scheduler_k3s.TriggerCorePostDeploy(appName)
|
||||||
|
case "core-post-extract":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
sourceWorkDir := flag.Arg(1)
|
||||||
|
err = scheduler_k3s.TriggerCorePostExtract(appName, sourceWorkDir)
|
||||||
case "install":
|
case "install":
|
||||||
err = scheduler_k3s.TriggerInstall()
|
err = scheduler_k3s.TriggerInstall()
|
||||||
case "post-app-clone-setup":
|
case "post-app-clone-setup":
|
||||||
@@ -32,6 +39,9 @@ func main() {
|
|||||||
oldAppName := flag.Arg(0)
|
oldAppName := flag.Arg(0)
|
||||||
newAppName := flag.Arg(1)
|
newAppName := flag.Arg(1)
|
||||||
err = scheduler_k3s.TriggerPostAppRenameSetup(oldAppName, newAppName)
|
err = scheduler_k3s.TriggerPostAppRenameSetup(oldAppName, newAppName)
|
||||||
|
case "post-create":
|
||||||
|
appName := flag.Arg(0)
|
||||||
|
err = scheduler_k3s.TriggerPostCreate(appName)
|
||||||
case "post-delete":
|
case "post-delete":
|
||||||
appName := flag.Arg(0)
|
appName := flag.Arg(0)
|
||||||
err = scheduler_k3s.TriggerPostDelete(appName)
|
err = scheduler_k3s.TriggerPostDelete(appName)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- $mappings := dict }}
|
{{- $mappings := dict }}
|
||||||
{{- if eq $processName "web" }}
|
{{- if hasKey $config "web" }}
|
||||||
{{- range $pdx, $port_map := $config.web.port_maps }}
|
{{- range $pdx, $port_map := $config.web.port_maps }}
|
||||||
{{- $mappings := set $mappings $port_map.name "true" }}
|
{{- $mappings := set $mappings $port_map.name "true" }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -61,7 +61,7 @@ spec:
|
|||||||
{{- range $config.args }}
|
{{- range $config.args }}
|
||||||
- {{ . }}
|
- {{ . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if eq $processName "web" }}
|
{{- if hasKey $config "web" }}
|
||||||
env:
|
env:
|
||||||
- name: PORT
|
- name: PORT
|
||||||
value: "{{ $.Values.global.network.primary_port }}"
|
value: "{{ $.Values.global.network.primary_port }}"
|
||||||
@@ -73,7 +73,7 @@ spec:
|
|||||||
image: {{ $.Values.global.image.name }}
|
image: {{ $.Values.global.image.name }}
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
name: {{ $.Values.global.app_name }}-{{ $processName }}
|
name: {{ $.Values.global.app_name }}-{{ $processName }}
|
||||||
{{- if eq $processName "web" }}
|
{{- if hasKey $config "web" }}
|
||||||
ports:
|
ports:
|
||||||
{{- range $pdx, $port_map := $config.web.port_maps }}
|
{{- range $pdx, $port_map := $config.web.port_maps }}
|
||||||
{{- if and (eq $port_map.scheme "https") (hasKey $mappings (printf "http-80-%.0f" $port_map.container_port)) }}
|
{{- if and (eq $port_map.scheme "https") (hasKey $mappings (printf "http-80-%.0f" $port_map.container_port)) }}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- $routeToKeda := false }}
|
{{- $routeToKeda := false }}
|
||||||
{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }}
|
{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }}
|
||||||
{{- if and ($.Capabilities.APIVersions.Has "http.keda.sh/v1alpha1") (and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http")) }}
|
{{- if and ($.Capabilities.APIVersions.Has "http.keda.sh/v1alpha1") (and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http")) }}
|
||||||
{{- $routeToKeda = true }}
|
{{- $routeToKeda = true }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}}
|
{{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}}
|
||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }}
|
{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }}
|
||||||
{{- if and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http") }}
|
{{- if and $config.autoscaling.http_trigger (eq $config.autoscaling.http_trigger.type "http") }}
|
||||||
{{- $mappings := dict }}
|
{{- $mappings := dict }}
|
||||||
{{- range $pdx, $port_map := $config.web.port_maps }}
|
{{- range $pdx, $port_map := $config.web.port_maps }}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}}
|
{{- if .Capabilities.APIVersions.Has "http.keda.sh/v1alpha1" -}}
|
||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{- if and (eq $processName "web") (and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda"))) }}
|
{{- if and $config.autoscaling (and $config.autoscaling.enabled (eq $config.autoscaling.type "keda")) }}
|
||||||
---
|
---
|
||||||
kind: Service
|
kind: Service
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}}
|
{{- if .Capabilities.APIVersions.Has "keda.sh/v1alpha1" -}}
|
||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{{- range $processName, $config := .Values.processes }}
|
{{- range $processName, $config := .Values.processes }}
|
||||||
# Skip cron jobs
|
{{- if not (hasKey $config "web") }}
|
||||||
{{- if and (hasKey $config "cron") (hasKey $config.cron "id") }}
|
# Skip {{ $processName }} as it doesn't have a web section
|
||||||
{{- continue }}
|
{{- continue }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,50 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/client/conditions"
|
"k8s.io/kubernetes/pkg/client/conditions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TriggerCorePostDeploy moves a configured kustomize root path to be in the app root dir
|
||||||
|
func TriggerCorePostDeploy(appName string) error {
|
||||||
|
return common.CorePostDeploy(common.CorePostDeployInput{
|
||||||
|
AppName: appName,
|
||||||
|
Destination: common.GetAppDataDirectory("scheduler-k3s", appName),
|
||||||
|
PluginName: "scheduler-k3s",
|
||||||
|
ExtractedPaths: []common.CorePostDeployPath{
|
||||||
|
{Path: "kustomization", IsDirectory: true},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TriggerCorePostExtract moves a configured kustomize root path to be in the app root dir
|
||||||
|
func TriggerCorePostExtract(appName string, sourceWorkDir string) error {
|
||||||
|
destination := common.GetAppDataDirectory("scheduler-k3s", appName)
|
||||||
|
kustomizeRootPath := getComputedKustomizeRootPath(appName)
|
||||||
|
return common.CorePostExtract(common.CorePostExtractInput{
|
||||||
|
AppName: appName,
|
||||||
|
Destination: destination,
|
||||||
|
PluginName: "scheduler-k3s",
|
||||||
|
SourceWorkDir: sourceWorkDir,
|
||||||
|
ToExtract: []common.CorePostExtractToExtract{
|
||||||
|
{
|
||||||
|
Path: kustomizeRootPath,
|
||||||
|
IsDirectory: true,
|
||||||
|
Name: "config/kustomize",
|
||||||
|
Destination: "kustomization",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TriggerInstall runs the install step for the scheduler-k3s plugin
|
// TriggerInstall runs the install step for the scheduler-k3s plugin
|
||||||
func TriggerInstall() error {
|
func TriggerInstall() error {
|
||||||
if err := common.PropertySetup("scheduler-k3s"); err != nil {
|
if err := common.PropertySetup("scheduler-k3s"); err != nil {
|
||||||
return fmt.Errorf("Unable to install the scheduler-k3s plugin: %s", err.Error())
|
return fmt.Errorf("Unable to install the scheduler-k3s plugin: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := common.SetupAppData("scheduler-k3s"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +102,11 @@ func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TriggerPostCreate creates the scheduler-k3s data directory
|
||||||
|
func TriggerPostCreate(appName string) error {
|
||||||
|
return common.CreateAppDataDirectory("scheduler-k3s", appName)
|
||||||
|
}
|
||||||
|
|
||||||
// TriggerPostDelete destroys the scheduler-k3s data for a given app container
|
// TriggerPostDelete destroys the scheduler-k3s data for a given app container
|
||||||
func TriggerPostDelete(appName string) error {
|
func TriggerPostDelete(appName string) error {
|
||||||
dataErr := common.RemoveAppDataDirectory("scheduler-k3s", appName)
|
dataErr := common.RemoveAppDataDirectory("scheduler-k3s", appName)
|
||||||
@@ -704,9 +748,15 @@ func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kustomizeRootPath := ""
|
||||||
|
if hasKustomizeDirectory(appName) {
|
||||||
|
kustomizeRootPath = getProcessSpecificKustomizeRootPath(appName)
|
||||||
|
}
|
||||||
|
|
||||||
common.LogInfo2(fmt.Sprintf("Installing %s", appName))
|
common.LogInfo2(fmt.Sprintf("Installing %s", appName))
|
||||||
err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{
|
err = helmAgent.InstallOrUpgradeChart(ctx, ChartInput{
|
||||||
ChartPath: chartPath,
|
ChartPath: chartPath,
|
||||||
|
KustomizeRootPath: kustomizeRootPath,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
ReleaseName: appName,
|
ReleaseName: appName,
|
||||||
RollbackOnFailure: allowRollbacks,
|
RollbackOnFailure: allowRollbacks,
|
||||||
|
|||||||
65
tests/unit/scheduler-k3s-3.bats
Normal file
65
tests/unit/scheduler-k3s-3.bats
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load test_helper
|
||||||
|
|
||||||
|
TEST_APP="rdmtestapp"
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
uninstall_k3s || true
|
||||||
|
global_setup
|
||||||
|
dokku nginx:stop
|
||||||
|
export KUBECONFIG="/etc/rancher/k3s/k3s.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown_() {
|
||||||
|
global_teardown
|
||||||
|
dokku nginx:start
|
||||||
|
uninstall_k3s || true
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "(scheduler-k3s) kustomize" {
|
||||||
|
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
|
||||||
|
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
INGRESS_CLASS=nginx install_k3s
|
||||||
|
|
||||||
|
run /bin/bash -c "dokku apps:create $TEST_APP"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP inject_kustomization_yaml
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run /bin/bash -c "kubectl get deployment $TEST_APP-web -o json | jq -r '.spec.replicas'"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output "3"
|
||||||
|
}
|
||||||
|
|
||||||
|
inject_kustomization_yaml() {
|
||||||
|
local APP="$1"
|
||||||
|
local APP_REPO_DIR="$2"
|
||||||
|
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||||
|
mkdir -p "$APP_REPO_DIR/config/kustomize"
|
||||||
|
touch "$APP_REPO_DIR/config/kustomize/kustomization.yaml"
|
||||||
|
cat <<EOF >"$APP_REPO_DIR/config/kustomize/kustomization.yaml"
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- rendered.yaml
|
||||||
|
patches:
|
||||||
|
- patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/replicas
|
||||||
|
value: 3
|
||||||
|
target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
EOF
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user