File helmify-0.4.18.obscpio of Package helmify

07070100000000000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001700000000helmify-0.4.18/.github07070100000001000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002100000000helmify-0.4.18/.github/workflows07070100000002000081A400000000000000000000000167C8625900000F8E000000000000000000000000000000000000002800000000helmify-0.4.18/.github/workflows/ci.ymlname: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

# GO tests
    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.21'
        cache: false

    - name: Fmt
      run: |
          # Run gofmt in "diff" mode to check for unformatted code
          UNFORMATTED_FILES=$(gofmt -l .)
          # Check if any files are unformatted
          if [[ -n "$UNFORMATTED_FILES" ]]; then
            echo "::error::The following Go files are not formatted correctly:"
            echo "$UNFORMATTED_FILES"  # List unformatted files in the log
            echo "::error::Please format your Go code by running \`go fmt ./...\` and commit the changes."
            exit 1  # Fail the check
          else
            echo "All Go files are properly formatted."
          fi
    - name: Vet
      run: go vet ./...

    - name: Test
      run: go test ./...

    - name: golangci-lint
      uses: golangci/golangci-lint-action@v3
      with:
        version: v1.54
# Generate example charts
    - name: Generate example charts
      run: |
          cat test_data/sample-app.yaml | go run ./cmd/helmify examples/app
          cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify examples/operator
    - name: Check that chart examples were commited
      run: |
          if [[ -n "$(git status --porcelain)" ]]; then
            # Capture the list of uncommitted files
            UNCOMMITTED_FILES=$(git status --porcelain)
            echo "::error::Chart examples generation step has uncommitted changes: $UNCOMMITTED_FILES
          Please run following commands and commit the results:
          - \`cat test_data/sample-app.yaml | go run ./cmd/helmify examples/app\`
          - \`cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify examples/operator\`"
            exit 1
          else
            echo "Chart examples generation check passed. No uncommitted changes."
          fi
# Dry-run generated charts in cluster
    - name: Install k8s cluster
      uses: helm/kind-action@v1.4.0
    - name: Install certs
      run: kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.1.1/cert-manager.yaml

    - name: Generate operator ci chart
      run: cat test_data/k8s-operator-ci.yaml | go run ./cmd/helmify examples/operator-ci
    - name: Fill operator ci secrets
      run: sed -i 's/""/"abc"/' ./examples/operator-ci/values.yaml
    - name: Dry-run operator in k8s cluster
      run: helm template ./examples/operator-ci -n operator-ns --create-namespace | kubectl apply --dry-run=server -f -

    - name: Generate app chart
      run: cat test_data/sample-app.yaml | go run ./cmd/helmify examples/app
    - name: Fill app secrets
      run: sed -i 's/""/"abc"/' ./examples/app/values.yaml
    - name: Dry-run app in k8s cluster
      run: helm template ./examples/app -n app-ns --create-namespace | kubectl apply --dry-run=server -f -

# Validate charts with Kubeconform
    - name: Install Kubeconform
      run: go install github.com/yannh/kubeconform/cmd/kubeconform@v0.6.1

    - name: Validate app
      run: helm template ./examples/app -n app-ns --create-namespace | kubeconform -schema-location 'https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/v3/apis__apiextensions.k8s.io__v1_openapi.json' -strict

    - name: Generate operator example chart
      run: cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify examples/operator
    - name: Fill operator example secrets
      run: sed -i 's/""/"abc"/' ./examples/operator/values.yaml
    - name: Validate example operator
      run: helm template ./examples/operator -n operator-ns --create-namespace | kubeconform -schema-location 'https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/v3/apis__apiextensions.k8s.io__v1_openapi.json' -strict
07070100000003000081A400000000000000000000000167C86259000001BF000000000000000000000000000000000000002D00000000helmify-0.4.18/.github/workflows/release.ymlname: Release Go Binaries

on:
  push:
    tags:
      - '*'

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-go@v3
        with:
          go-version: '1.21'
      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v2
        with:
          version: v1.26.2
          args: release --rm-dist
        env:
          GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
07070100000004000081A400000000000000000000000167C86259000001A6000000000000000000000000000000000000001A00000000helmify-0.4.18/.gitignore
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin
testbin/*

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Kubernetes Generated files - skip generated files, except for vendored files

!vendor/**/zz_generated.*

# editor and IDE paraphernalia
.idea
*.swp
*.swo
*~
# VSCode devcontainer/codespace
.devcontainer/

dist/

07070100000005000081A400000000000000000000000167C86259000005B5000000000000000000000000000000000000001E00000000helmify-0.4.18/.golangci.yamlrun:
  tests: false
  skip-dirs:
    - internal
go: 1.21

fix: true

linters-settings:
  maligned:
    suggest-new: true
  staticcheck:
    go: "1.21"
    checks: [ "all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022","-SA6005","-SA1019" ]
  gocritic:
    disabled-checks:
      - captLocal
      - commentFormatting
  revive:
    rules:
      - name: var-naming
        disabled: true
  nolintlint:
    require-explanation: true

linters:
  disable-all: true
  enable:
    - asasalint # check for pass []any as any in variadic func(...any)
    - asciicheck # simple linter to check that your code does not contain non-ASCII identifiers
    - errchkjson # checks types passed to the json encoding functions
    - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13
    - exportloopref # checks for pointers to enclosing loop variables
    - gocritic # provides diagnostics that check for bugs, performance and style issues
    - revive # fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint
    - nolintlint # requiresw to write notes why linter is disabled
    - errcheck
    - staticcheck
    - typecheck
    - unused
    - govet
    - ineffassign
    - gosimple
    - durationcheck
    - errchkjson
    - errorlint
    - makezero
    - exportloopref
    - errchkjson
    - prealloc
    - deadcode
07070100000006000081A400000000000000000000000167C86259000004C1000000000000000000000000000000000000001F00000000helmify-0.4.18/.goreleaser.ymlproject_name: helmify
before:
  hooks:
    - go mod tidy
builds:
  - main: ./cmd/helmify
    env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin
    ignore:
      - goos: darwin
        goarch: 386
      - goos: darwin
        goarch: arm
      - goos: windows
        goarch: arm
      - goos: windows
        goarch: arm64
archives:
  -
    name_template: >-
      {{ .ProjectName }}_
      {{- title .Os }}_
      {{- if eq .Arch "amd64" }}x86_64
      {{- else if eq .Arch "386" }}i386
      {{- else }}{{ .Arch }}{{ end }}
    format_overrides:
      - goos: windows
        format: zip
    files:
      - none*
checksum:
  name_template: 'checksums.txt'
brews:
  -
    tap:
      owner: arttor
      name: homebrew-tap
    commit_author:
      name: arttor
      email: torubarov-a-a@yandex.ru
    commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}"
    folder: Formula
    homepage: "https://github.com/arttor/helmify"
    description: "Creates Helm chart from Kubernetes yaml."
    license: "MIT"
    test: |
      system "#{bin}/helmify --version"
    install: |
      bin.install "helmify"
release:
  github:
    owner: arttor
    name: helmify07070100000007000081A400000000000000000000000167C8625900000427000000000000000000000000000000000000001700000000helmify-0.4.18/LICENSEMIT License

Copyright (c) 2021 arttor

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
07070100000008000081A400000000000000000000000167C8625900002C89000000000000000000000000000000000000001900000000helmify-0.4.18/README.md# Helmify
[![CI](https://github.com/arttor/helmify/actions/workflows/ci.yml/badge.svg)](https://github.com/arttor/helmify/actions/workflows/ci.yml)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/arttor/helmify)
![GitHub](https://img.shields.io/github/license/arttor/helmify)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/arttor/helmify)
[![Go Report Card](https://goreportcard.com/badge/github.com/arttor/helmify)](https://goreportcard.com/report/github.com/arttor/helmify)
[![GoDoc](https://godoc.org/github.com/arttor/helmify?status.svg)](https://pkg.go.dev/github.com/arttor/helmify?tab=doc)
![GitHub total downloads](https://img.shields.io/github/downloads/arttor/helmify/total)

CLI that creates [Helm](https://github.com/helm/helm) charts from kubernetes manifests.

Helmify reads a list of [supported k8s objects](#status) from stdin and converts it to a helm chart. 
Designed to generate charts for [k8s operators](#integrate-to-your-operator-sdkkubebuilder-project) but not limited to.
See [examples](https://github.com/arttor/helmify/tree/main/examples) of charts generated by helmify.

Supports `Helm >=v3.6.0`

Submit issue if some features missing for your use-case.

## Usage

1) As pipe:

    ```shell
    cat my-app.yaml | helmify mychart
    ```
   Will create 'mychart' directory with Helm chart from yaml file with k8s objects.

    ```shell
    awk 'FNR==1 && NR!=1  {print "---"}{print}' /<my_directory>/*.yaml | helmify mychart
    ```
   Will create 'mychart' directory with Helm chart from all yaml files in `<my_directory> `directory.

2) From filesystem:
    ```shell
    helmify -f /my_directory/my-app.yaml mychart
    ```
    Will create 'mychart' directory with Helm chart from `my_directory/my-app.yaml`.
    ```shell
    helmify -f /my_directory mychart
    ```
    Will create 'mychart' directory with Helm chart from all yaml files in `<my_directory> `directory.
    ```shell
    helmify -f /my_directory -r mychart
    ```
    Will create 'mychart' directory with Helm chart from all yaml files in `<my_directory> `directory recursively.
    ```shell
    helmify -f ./first_dir -f ./second_dir/my_deployment.yaml -f ./third_dir  mychart
    ```
    Will create 'mychart' directory with Helm chart from multiple directories and files.


3) From [kustomize](https://kustomize.io/) output:
    ```shell
    kustomize build <kustomize_dir> | helmify mychart
    ```
    Will create 'mychart' directory with Helm chart from kustomize output.

### Integrate to your Operator-SDK/Kubebuilder project

1. Open `Makefile` in your operator project generated by 
   [Operator-SDK](https://github.com/operator-framework/operator-sdk) or [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder).
2. Add these lines to `Makefile`:
- With operator-sdk version < v1.23.0 
    ```makefile
    HELMIFY = $(shell pwd)/bin/helmify
    helmify:
    	$(call go-get-tool,$(HELMIFY),github.com/arttor/helmify/cmd/helmify@v0.3.7)
    
    helm: manifests kustomize helmify
    	$(KUSTOMIZE) build config/default | $(HELMIFY)
    ```
- With operator-sdk version >= v1.23.0
    ```makefile
    HELMIFY ?= $(LOCALBIN)/helmify
    
    .PHONY: helmify
    helmify: $(HELMIFY) ## Download helmify locally if necessary.
    $(HELMIFY): $(LOCALBIN)
    	test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest
        
    helm: manifests kustomize helmify
    	$(KUSTOMIZE) build config/default | $(HELMIFY)
    ```
3. Run `make helm` in project root. It will generate helm chart with name 'chart' in 'chart' directory.

## Install

With [Homebrew](https://brew.sh/) (for MacOS or Linux): `brew install arttor/tap/helmify`

Or download suitable for your system binary from [the Releases page](https://github.com/arttor/helmify/releases/latest).
Unpack the helmify binary and add it to your PATH and you are good to go!

## Available options
Helmify takes a chart name for an argument.
Usage:

```helmify [flags] CHART_NAME```  -  `CHART_NAME` is optional. Default is 'chart'. Can be a directory, e.g. 'deploy/charts/mychart'.

| flag                      | description                                                                                                                                                                                                 | sample                              |
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|
| -h -help                  | Prints help                                                                                                                                                                                                 | `helmify -h`                        |
| -f                        | File source for k8s manifests (directory or file), multiple sources supported                                                                                                                               | `helmify -f ./test_data`            |
| -r                        | Scan file directory recursively. Used only if -f provided                                                                                                                                                   | `helmify -f ./test_data -r`         |
| -v                        | Enable verbose output. Prints WARN and INFO.                                                                                                                                                                | `helmify -v`                        |
| -vv                       | Enable very verbose output. Also prints DEBUG.                                                                                                                                                              | `helmify -vv`                       |
| -version                  | Print helmify version.                                                                                                                                                                                      | `helmify -version`                  |
| -crd-dir                  | Place crds in their own folder per Helm 3 [docs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#method-1-let-helm-do-it-for-you). Caveat: CRDs templating is not supported by Helm. | `helmify -crd-dir`                  |
| -image-pull-secrets       | Allows the user to use existing secrets as imagePullSecrets                                                                                                                                                 | `helmify -image-pull-secrets`       |
| -original-name            | Use the object's original name instead of adding the chart's release name as the common prefix.                                                                                                             | `helmify -original-name`            |
| -cert-manager-as-subchart | Allows the user to install cert-manager as a subchart                                                                                                                                                       | `helmify -cert-manager-as-subchart` |
| -cert-manager-version     | Allows the user to specify cert-manager subchart version. Only useful with cert-manager-as-subchart. (default "v1.12.2")                                                                                    | `helmify -cert-manager-version=v1.12.2`    |
| -cert-manager-install-crd     | Allows the user to install cert-manager CRD as part of the cert-manager subchart.(default "true")                                                                                                           | `helmify -cert-manager-install-crd` |
| -preserve-ns              | Allows users to use the object's original namespace instead of adding all the resources to a common namespace. (default "false")                                                                            | `helmify -preserve-ns`              |
| -add-webhook-option | Adds an option to enable/disable webhook installation  | `helmify -add-webhook-option`|
## Status
Supported k8s resources:
- Deployment, DaemonSet, StatefulSet
- Job, CronJob
- Service, Ingress
- PersistentVolumeClaim
- RBAC (ServiceAccount, (cluster-)role, (cluster-)roleBinding)
- configs (ConfigMap, Secret)
- webhooks (cert, issuer, ValidatingWebhookConfiguration)
- custom resource definitions (CRD)

### Known issues
- Helmify will not overwrite `Chart.yaml` file if presented. Done on purpose.
- Helmify will not delete existing template files, only overwrite.
- Helmify overwrites templates and values files on every run. 
  This means that all your manual changes in helm template files will be lost on the next run.
- if switching between the using the `-crd-dir` flag it is better to delete and regenerate the from scratch to ensure crds are not accidentally spliced/formatted into the same chart. Bear in mind you will want to update your `Chart.yaml` thereafter.
  
## Develop
To support a new type of k8s object template:
1. Implement `helmify.Processor` interface. Place implementation in `pkg/processor`. The package contains 
examples for most k8s objects.
2. Register your processor in the `pkg/app/app.go`
3. Add relevant input sample to `test_data/kustomize.output`.


### Run
Clone repo and execute command:

```shell
cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify mychart
```

Will generate `mychart` Helm chart form file `test_data/k8s-operator-kustomize.output` representing typical operator
[kustomize](https://github.com/kubernetes-sigs/kustomize) output.

### Test
For manual testing, run program with debug output:
```shell
cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify -vv mychart
```
Then inspect logs and generated chart in `./mychart` directory.

To execute tests, run:
```shell
go test ./...
```
Beside unit-tests, project contains e2e test `pkg/app/app_e2e_test.go`.
It's a go test, which uses `test_data/*` to generate a chart in temporary directory. 
Then runs `helm lint --strict` to check if generated chart is valid.

## Contribute

Following rules will help changes to be accepted faster:
- For more than one-line bugfixes consider creating an issue with bug description or feature request
- For feature request try to think about and cover following topics (when applicable):
  - Motivation: why feature is needed? Which problem does it solve? What is current workaround?
  - Backward-compatibility: existing users expect that after upgrading helmify version their existing generated charts wont be changed without consent.
- For bugfix PR consider adding example to [/test_data](./test_data/) source yamls reproducing bug.

### Contribution flow

Check list before submitting PR:
1. Run `go fmt ./...`
2. Run tests `go test ./...`
3. Update chart examples:
   ```shell
   cat test_data/sample-app.yaml | go run ./cmd/helmify examples/app
   ```
   ```shell
   cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify examples/operator
   ```
4. In case of long commit history (more than 3) squash local commits into one
07070100000009000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001300000000helmify-0.4.18/cmd0707010000000A000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001B00000000helmify-0.4.18/cmd/helmify0707010000000B000081A400000000000000000000000167C8625900001104000000000000000000000000000000000000002400000000helmify-0.4.18/cmd/helmify/flags.gopackage main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/arttor/helmify/pkg/config"
)

const helpText = `Helmify parses kubernetes resources from std.in and converts it to a Helm chart.

Example 1: 'kustomize build <kustomize_dir> | helmify mychart' 
  - will create 'mychart' directory with Helm chart from kustomize output.

Example 2: 'cat my-app.yaml | helmify mychart' 
  - will create 'mychart' directory with Helm chart from yaml file.

Example 3: 'helmify -f ./test_data/dir  mychart' 
  - will scan directory ./test_data/dir for files with k8s manifests and create 'mychart' directory with Helm chart.

Example 4: 'helmify -f ./test_data/dir -r  mychart' 
  - will scan directory ./test_data/dir recursively and  create 'mychart' directory with Helm chart.

Example 5: 'helmify -f ./test_data/dir -f ./test_data/sample-app.yaml -f ./test_data/dir/another_dir  mychart' 
  - will scan provided multiple files and directories and  create 'mychart' directory with Helm chart.

Example 6: 'awk 'FNR==1 && NR!=1  {print "---"}{print}' /my_directory/*.yaml | helmify mychart' 
  - will create 'mychart' directory with Helm chart from all yaml files in my_directory directory.

Usage:
  helmify [flags] CHART_NAME  -  CHART_NAME is optional. Default is 'chart'. Can be a directory, e.g. 'deploy/charts/mychart'.

Flags:
`

type arrayFlags []string

func (i *arrayFlags) String() string {
	if i == nil || len(*i) == 0 {
		return ""
	}
	return strings.Join(*i, ", ")
}

func (i *arrayFlags) Set(value string) error {
	*i = append(*i, value)
	return nil
}

// ReadFlags command-line flags into app config.
func ReadFlags() config.Config {
	files := arrayFlags{}
	result := config.Config{}
	var h, help, version, crd, preservens bool
	flag.BoolVar(&h, "h", false, "Print help. Example: helmify -h")
	flag.BoolVar(&help, "help", false, "Print help. Example: helmify -help")
	flag.BoolVar(&version, "version", false, "Print helmify version. Example: helmify -version")
	flag.BoolVar(&result.Verbose, "v", false, "Enable verbose output (print WARN & INFO). Example: helmify -v")
	flag.BoolVar(&result.VeryVerbose, "vv", false, "Enable very verbose output. Same as verbose but with DEBUG. Example: helmify -vv")
	flag.BoolVar(&crd, "crd-dir", false, "Enable crd install into 'crds' directory.\nWarning: CRDs placed in 'crds' directory will not be templated by Helm.\nSee https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations\nExample: helmify -crd-dir")
	flag.BoolVar(&result.ImagePullSecrets, "image-pull-secrets", false, "Allows the user to use existing secrets as imagePullSecrets in values.yaml")
	flag.BoolVar(&result.GenerateDefaults, "generate-defaults", false, "Allows the user to add empty placeholders for typical customization options in values.yaml. Currently covers: topology constraints, node selectors, tolerances")
	flag.BoolVar(&result.CertManagerAsSubchart, "cert-manager-as-subchart", false, "Allows the user to add cert-manager as a subchart")
	flag.StringVar(&result.CertManagerVersion, "cert-manager-version", "v1.12.2", "Allows the user to specify cert-manager subchart version. Only useful with cert-manager-as-subchart.")
	flag.BoolVar(&result.CertManagerInstallCRD, "cert-manager-install-crd", true, "Allows the user to install cert-manager CRD. Only useful with cert-manager-as-subchart.")
	flag.BoolVar(&result.FilesRecursively, "r", false, "Scan dirs from -f option recursively")
	flag.BoolVar(&result.OriginalName, "original-name", false, "Use the object's original name instead of adding the chart's release name as the common prefix.")
	flag.Var(&files, "f", "File or directory containing k8s manifests")
	flag.BoolVar(&preservens, "preserve-ns", false, "Use the object's original namespace instead of adding all the resources to a common namespace")
	flag.BoolVar(&result.AddWebhookOption, "add-webhook-option", false, "Allows the user to add webhook option in values.yaml")

	flag.Parse()
	if h || help {
		fmt.Print(helpText)
		flag.PrintDefaults()
		os.Exit(0)
	}
	if version {
		printVersion()
		os.Exit(0)
	}
	name := flag.Arg(0)
	if name != "" {
		result.ChartName = filepath.Base(name)
		result.ChartDir = filepath.Dir(name)
	}
	if crd {
		result.Crd = crd
	}
	if preservens {
		result.PreserveNs = true
	}
	result.Files = files
	return result
}
0707010000000C000081A400000000000000000000000167C86259000001F0000000000000000000000000000000000000002300000000helmify-0.4.18/cmd/helmify/main.gopackage main

import (
	"os"

	"github.com/arttor/helmify/pkg/app"
	"github.com/sirupsen/logrus"
)

func main() {
	conf := ReadFlags()
	stat, err := os.Stdin.Stat()
	if err != nil {
		logrus.WithError(err).Error("stdin error")
		os.Exit(1)
	}
	if len(conf.Files) == 0 && (stat.Mode()&os.ModeCharDevice) != 0 {
		logrus.Error("no data piped in stdin")
		os.Exit(1)
	}
	if err = app.Start(os.Stdin, conf); err != nil {
		logrus.WithError(err).Error("helmify finished with error")
		os.Exit(1)
	}
}
0707010000000D000081A400000000000000000000000167C8625900000154000000000000000000000000000000000000002600000000helmify-0.4.18/cmd/helmify/version.gopackage main

import (
	"fmt"
)

// these information will be collected when build, by `-ldflags "-X main.version=0.1"`.
var (
	version = "development"
	date    = "not set"
	commit  = "not set"
)

func printVersion() {
	fmt.Printf("Version:    %s\n", version)
	fmt.Printf("Build Time: %s\n", date)
	fmt.Printf("Git Commit: %s\n", commit)
}
0707010000000E000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001800000000helmify-0.4.18/examples0707010000000F000081A400000000000000000000000167C8625900000303000000000000000000000000000000000000002200000000helmify-0.4.18/examples/README.md# Examples
`app` - helm chart generated by helmify from [test_data/sample-app.yaml](https://github.com/arttor/helmify/blob/main/test_data/sample-app.yaml). 
Represents typical k8s app with Deployment, Service, ConfigMap, Secret.
Generated with: `cat test_data/sample-app.yaml | go run ./cmd/helmify examples/app`

`operator` - helm chart generated by helmify from [test_data/k8s-operator-kustomize.output](https://github.com/arttor/helmify/blob/main/test_data/k8s-operator-kustomize.output). 
Represents typical k8s operator build with [Operator-SDK](https://github.com/operator-framework/operator-sdk) or [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder).
Generated with: `cat test_data/k8s-operator-kustomize.output | go run ./cmd/helmify examples/operator`07070100000010000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001C00000000helmify-0.4.18/examples/app07070100000011000081A400000000000000000000000167C862590000015D000000000000000000000000000000000000002800000000helmify-0.4.18/examples/app/.helmignore# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
07070100000012000081A400000000000000000000000167C862590000046F000000000000000000000000000000000000002700000000helmify-0.4.18/examples/app/Chart.yamlapiVersion: v2
name: app
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"
07070100000013000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002600000000helmify-0.4.18/examples/app/templates07070100000014000081A400000000000000000000000167C86259000006CE000000000000000000000000000000000000003300000000helmify-0.4.18/examples/app/templates/_helpers.tpl{{/*
Expand the name of the chart.
*/}}
{{- define "app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "app.labels" -}}
helm.sh/chart: {{ include "app.chart" . }}
{{ include "app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "app.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "app.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
07070100000015000081A400000000000000000000000167C862590000028C000000000000000000000000000000000000003500000000helmify-0.4.18/examples/app/templates/batch-job.yamlapiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "app.fullname" . }}-batch-job
  labels:
  {{- include "app.labels" . | nindent 4 }}
spec:
  backoffLimit: {{ .Values.batchJob.backoffLimit }}
  template:
    spec:
      containers:
      - command:
        - perl
        - -Mbignum=bpi
        - -wle
        - print bpi(2000)
        env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.batchJob.pi.image.repository }}:{{ .Values.batchJob.pi.image.tag
          | default .Chart.AppVersion }}
        name: pi
        resources: {}
      restartPolicy: Never
07070100000016000081A400000000000000000000000167C862590000033E000000000000000000000000000000000000003400000000helmify-0.4.18/examples/app/templates/cron-job.yamlapiVersion: batch/v1
kind: CronJob
metadata:
  name: {{ include "app.fullname" . }}-cron-job
  labels:
  {{- include "app.labels" . | nindent 4 }}
spec:
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
            env:
            - name: KUBERNETES_CLUSTER_DOMAIN
              value: {{ quote .Values.kubernetesClusterDomain }}
            image: {{ .Values.cronJob.hello.image.repository }}:{{ .Values.cronJob.hello.image.tag
              | default .Chart.AppVersion }}
            imagePullPolicy: {{ .Values.cronJob.hello.imagePullPolicy }}
            name: hello
            resources: {}
          restartPolicy: OnFailure
  schedule: {{ .Values.cronJob.schedule | quote }}
07070100000017000081A400000000000000000000000167C86259000005B6000000000000000000000000000000000000003500000000helmify-0.4.18/examples/app/templates/daemonset.yamlapiVersion: apps/v1
kind: DaemonSet
metadata:
  name: {{ include "app.fullname" . }}-fluentd-elasticsearch
  labels:
    k8s-app: fluentd-logging
  {{- include "app.labels" . | nindent 4 }}
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
    {{- include "app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
      {{- include "app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.fluentdElasticsearch.fluentdElasticsearch.image.repository }}:{{
          .Values.fluentdElasticsearch.fluentdElasticsearch.image.tag | default .Chart.AppVersion
          }}
        name: fluentd-elasticsearch
        resources: {{- toYaml .Values.fluentdElasticsearch.fluentdElasticsearch.resources
          | nindent 10 }}
        volumeMounts:
        - mountPath: /var/log
          name: varlog
        - mountPath: /var/lib/docker/containers
          name: varlibdockercontainers
          readOnly: true
      terminationGracePeriodSeconds: 30
      tolerations:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
        operator: Exists
      volumes:
      - hostPath:
          path: /var/log
        name: varlog
      - hostPath:
          path: /var/lib/docker/containers
        name: varlibdockercontainers
07070100000018000081A400000000000000000000000167C8625900000EEF000000000000000000000000000000000000003600000000helmify-0.4.18/examples/app/templates/deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "app.fullname" . }}-myapp
  labels:
    app: myapp
  {{- include "app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.myapp.replicas }}
  revisionHistoryLimit: {{ .Values.myapp.revisionHistoryLimit }}
  selector:
    matchLabels:
      app: myapp
    {{- include "app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        app: myapp
      {{- include "app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - args: {{- toYaml .Values.myapp.app.args | nindent 8 }}
        command:
        - /manager
        env:
        - name: VAR1
          valueFrom:
            secretKeyRef:
              key: VAR1
              name: {{ include "app.fullname" . }}-my-secret-vars
        - name: VAR2
          valueFrom:
            secretKeyRef:
              key: VAR2
              name: {{ include "app.fullname" . }}-my-secret-vars
        - name: APP_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app.kubernetes.io/name']
        - name: INSTANCE_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app.kubernetes.io/instance']
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.myapp.app.image.repository }}:{{ .Values.myapp.app.image.tag
          | default .Chart.AppVersion }}
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: app
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources: {{- toYaml .Values.myapp.app.resources | nindent 10 }}
        securityContext: {{- toYaml .Values.myapp.app.containerSecurityContext | nindent
          10 }}
        volumeMounts:
        - mountPath: /my_config.properties
          name: manager-config
          subPath: my_config.properties
        - mountPath: /my.ca
          name: secret-volume
        - mountPath: /etc/props
          name: props
        - mountPath: /usr/share/nginx/html
          name: sample-pv-storage
      - args: {{- toYaml .Values.myapp.proxySidecar.args | nindent 8 }}
        env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.myapp.proxySidecar.image.repository }}:{{ .Values.myapp.proxySidecar.image.tag
          | default .Chart.AppVersion }}
        name: proxy-sidecar
        ports:
        - containerPort: 8443
          name: https
        resources: {}
      initContainers:
      - command:
        - /bin/sh
        - -c
        - echo 'Initializing container...'
        env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.myapp.initContainer.image.repository }}:{{ .Values.myapp.initContainer.image.tag
          | default .Chart.AppVersion }}
        name: init-container
        resources: {}
      nodeSelector: {{- toYaml .Values.myapp.nodeSelector | nindent 8 }}
      securityContext: {{- toYaml .Values.myapp.podSecurityContext | nindent 8 }}
      terminationGracePeriodSeconds: 10
      volumes:
      - configMap:
          name: {{ include "app.fullname" . }}-my-config
        name: manager-config
      - configMap:
          name: {{ include "app.fullname" . }}-my-config-props
        name: props
      - name: secret-volume
        secret:
          secretName: {{ include "app.fullname" . }}-my-secret-ca
      - name: sample-pv-storage
        persistentVolumeClaim:
          claimName: {{ include "app.fullname" . }}-my-sample-pv-claim
07070100000019000081A400000000000000000000000167C862590000018C000000000000000000000000000000000000003B00000000helmify-0.4.18/examples/app/templates/my-config-props.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "app.fullname" . }}-my-config-props
  labels:
  {{- include "app.labels" . | nindent 4 }}
data:
  my.prop1: {{ .Values.myConfigProps.myProp1 | quote }}
  my.prop2: {{ .Values.myConfigProps.myProp2 | quote }}
  my.prop3: {{ .Values.myConfigProps.myProp3 | quote }}
  myval.yaml: {{ .Values.myConfigProps.myvalYaml | toYaml | indent 1 }}
0707010000001A000081A400000000000000000000000167C86259000001D6000000000000000000000000000000000000003500000000helmify-0.4.18/examples/app/templates/my-config.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "app.fullname" . }}-my-config
  labels:
  {{- include "app.labels" . | nindent 4 }}
immutable: true
data:
  dummyconfigmapkey: {{ .Values.myConfig.dummyconfigmapkey | quote }}
  my_config.properties: |
    health.healthProbeBindAddress={{ .Values.myConfig.myConfigProperties.health.healthProbeBindAddress | quote }}
    metrics.bindAddress={{ .Values.myConfig.myConfigProperties.metrics.bindAddress | quote }}
0707010000001B000081A400000000000000000000000167C86259000001CC000000000000000000000000000000000000003E00000000helmify-0.4.18/examples/app/templates/my-sample-pv-claim.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: {{ include "app.fullname" . }}-my-sample-pv-claim
  labels:
  {{- include "app.labels" . | nindent 4 }}
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    limits:
      storage: {{ .Values.pvc.mySamplePvClaim.storageLimit | quote }}
    requests:
      storage: {{ .Values.pvc.mySamplePvClaim.storageRequest | quote }}
  storageClassName: {{ .Values.pvc.mySamplePvClaim.storageClass | quote }}
0707010000001C000081A400000000000000000000000167C8625900000109000000000000000000000000000000000000003800000000helmify-0.4.18/examples/app/templates/my-secret-ca.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "app.fullname" . }}-my-secret-ca
  labels:
  {{- include "app.labels" . | nindent 4 }}
data:
  ca.crt: {{ required "mySecretCa.caCrt is required" .Values.mySecretCa.caCrt | b64enc
    | quote }}
type: opaque
0707010000001D000081A400000000000000000000000167C86259000002A1000000000000000000000000000000000000003A00000000helmify-0.4.18/examples/app/templates/my-secret-vars.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "app.fullname" . }}-my-secret-vars
  labels:
  {{- include "app.labels" . | nindent 4 }}
data:
  ELASTIC_FOOBAR_HUNTER123_MEOWTOWN_VERIFY: {{ required "mySecretVars.elasticFoobarHunter123MeowtownVerify is required" .Values.mySecretVars.elasticFoobarHunter123MeowtownVerify | b64enc
    | quote }}
  VAR1: {{ required "mySecretVars.var1 is required" .Values.mySecretVars.var1 | b64enc
    | quote }}
  VAR2: {{ required "mySecretVars.var2 is required" .Values.mySecretVars.var2 | b64enc
    | quote }}
stringData:
  str: {{ required "mySecretVars.str is required" .Values.mySecretVars.str | quote
    }}
type: opaque
0707010000001E000081A400000000000000000000000167C86259000001CE000000000000000000000000000000000000003900000000helmify-0.4.18/examples/app/templates/myapp-ingress.yamlapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "app.fullname" . }}-myapp-ingress
  labels:
  {{- include "app.labels" . | nindent 4 }}
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - backend:
          service:
            name: '{{ include "app.fullname" . }}-myapp-service'
            port:
              number: 8443
        path: /testpath
        pathType: Prefix
0707010000001F000081A400000000000000000000000167C86259000001D3000000000000000000000000000000000000003C00000000helmify-0.4.18/examples/app/templates/myapp-lb-service.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "app.fullname" . }}-myapp-lb-service
  labels:
    app: myapp
  {{- include "app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.myappLbService.type }}
  selector:
    app: myapp
    {{- include "app.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.myappLbService.ports | toYaml | nindent 2 }}
  loadBalancerSourceRanges:
  {{- .Values.myappLbService.loadBalancerSourceRanges | toYaml | nindent 2 }}
07070100000020000081A400000000000000000000000167C8625900000186000000000000000000000000000000000000003500000000helmify-0.4.18/examples/app/templates/myapp-pdb.yamlapiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: {{ include "app.fullname" . }}-myapp-pdb
  labels:
    app: nginx
  {{- include "app.labels" . | nindent 4 }}
spec:
  minAvailable: {{ .Values.myappPdb.minAvailable }}
  maxUnavailable: {{ .Values.myappPdb.maxUnavailable }}
  selector:
    matchLabels:
      app: nginx
    {{- include "app.selectorLabels" . | nindent 6 }}
07070100000021000081A400000000000000000000000167C8625900000162000000000000000000000000000000000000003900000000helmify-0.4.18/examples/app/templates/myapp-service.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "app.fullname" . }}-myapp-service
  labels:
    app: myapp
  {{- include "app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.myappService.type }}
  selector:
    app: myapp
    {{- include "app.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.myappService.ports | toYaml | nindent 2 }}
07070100000022000081A400000000000000000000000167C862590000014C000000000000000000000000000000000000003100000000helmify-0.4.18/examples/app/templates/nginx.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "app.fullname" . }}-nginx
  labels:
    app: nginx
  {{- include "app.labels" . | nindent 4 }}
spec:
  type: {{ .Values.nginx.type }}
  selector:
    app: nginx
    {{- include "app.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.nginx.ports | toYaml | nindent 2 }}
07070100000023000081A400000000000000000000000167C862590000040E000000000000000000000000000000000000003700000000helmify-0.4.18/examples/app/templates/statefulset.yamlapiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ include "app.fullname" . }}-web
  labels:
  {{- include "app.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.web.replicas }}
  selector:
    matchLabels:
      app: nginx
  serviceName: {{ include "app.fullname" . }}-nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.web.nginx.image.repository }}:{{ .Values.web.nginx.image.tag
          | default .Chart.AppVersion }}
        name: nginx
        ports:
        - containerPort: 80
          name: web
        resources: {}
        volumeMounts:
        - mountPath: /usr/share/nginx/html
          name: www
  updateStrategy: {}
  volumeClaimTemplates:
  - metadata:
      creationTimestamp: null
      name: www
    spec:
      accessModes:
      - ReadWriteOnce
      resources: {{ .Values.web.volumeClaims.www | toYaml | nindent 8 }}
07070100000024000081A400000000000000000000000167C86259000009DF000000000000000000000000000000000000002800000000helmify-0.4.18/examples/app/values.yamlbatchJob:
  backoffLimit: 4
  pi:
    image:
      repository: perl
      tag: 5.34.0
cronJob:
  hello:
    image:
      repository: busybox
      tag: "1.28"
    imagePullPolicy: IfNotPresent
  schedule: '* * * * *'
fluentdElasticsearch:
  fluentdElasticsearch:
    image:
      repository: quay.io/fluentd_elasticsearch/fluentd
      tag: v2.5.2
    resources:
      limits:
        memory: 200Mi
      requests:
        cpu: 100m
        memory: 200Mi
kubernetesClusterDomain: cluster.local
myConfig:
  dummyconfigmapkey: dummyconfigmapvalue
  myConfigProperties:
    health:
      healthProbeBindAddress: "8081"
    metrics:
      bindAddress: 127.0.0.1:8080
myConfigProps:
  myProp1: "1"
  myProp2: val 1
  myProp3: "true"
  myvalYaml: |-
    apiVersion: clickhouse.altinity.com/v1
    kind: ClickHouseInstallationTemplate
    metadata:
      name: default-oneperhost-pod-template
    spec:
      templates:
        podTemplates:
          - name: default-oneperhost-pod-template
            distribution: "OnePerHost"
mySecretCa:
  caCrt: ""
mySecretVars:
  elasticFoobarHunter123MeowtownVerify: ""
  str: ""
  var1: ""
  var2: ""
myapp:
  app:
    args:
    - --health-probe-bind-address=:8081
    - --metrics-bind-address=127.0.0.1:8080
    - --leader-elect
    containerSecurityContext:
      allowPrivilegeEscalation: false
    image:
      repository: controller
      tag: latest
    resources:
      limits:
        cpu: 100m
        memory: 30Mi
      requests:
        cpu: 100m
        memory: 20Mi
  initContainer:
    image:
      repository: bash
      tag: latest
  nodeSelector:
    region: east
    type: user-node
  podSecurityContext:
    fsGroup: 20000
    runAsNonRoot: true
    runAsUser: 65532
  proxySidecar:
    args:
    - --secure-listen-address=0.0.0.0:8443
    - --v=10
    image:
      repository: gcr.io/kubebuilder/kube-rbac-proxy
      tag: v0.8.0
  replicas: 3
  revisionHistoryLimit: 5
myappLbService:
  loadBalancerSourceRanges:
  - 10.0.0.0/8
  ports:
  - name: https
    port: 8443
    targetPort: https
  type: LoadBalancer
myappPdb:
  minAvailable: 2
myappService:
  ports:
  - name: https
    port: 8443
    targetPort: https
  type: ClusterIP
nginx:
  ports:
  - name: web
    port: 80
    targetPort: 0
  type: ClusterIP
pvc:
  mySamplePvClaim:
    storageClass: manual
    storageLimit: 5Gi
    storageRequest: 3Gi
web:
  nginx:
    image:
      repository: registry.k8s.io/nginx-slim
      tag: "0.8"
  replicas: 2
  volumeClaims:
    www:
      requests:
        storage: 1Gi
07070100000025000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002100000000helmify-0.4.18/examples/operator07070100000026000081A400000000000000000000000167C862590000015D000000000000000000000000000000000000002D00000000helmify-0.4.18/examples/operator/.helmignore# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
07070100000027000081A400000000000000000000000167C8625900000474000000000000000000000000000000000000002C00000000helmify-0.4.18/examples/operator/Chart.yamlapiVersion: v2
name: operator
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"
07070100000028000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002B00000000helmify-0.4.18/examples/operator/templates07070100000029000081A400000000000000000000000167C8625900000700000000000000000000000000000000000000003800000000helmify-0.4.18/examples/operator/templates/_helpers.tpl{{/*
Expand the name of the chart.
*/}}
{{- define "operator.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "operator.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "operator.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "operator.labels" -}}
helm.sh/chart: {{ include "operator.chart" . }}
{{ include "operator.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "operator.selectorLabels" -}}
app.kubernetes.io/name: {{ include "operator.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "operator.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "operator.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
0707010000002A000081A400000000000000000000000167C862590000278C000000000000000000000000000000000000003F00000000helmify-0.4.18/examples/operator/templates/cephvolume-crd.yamlapiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: cephvolumes.test.example.com
  annotations:
    cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "operator.fullname"
      . }}-serving-cert'
    example-annotation: xyz
  labels:
    example-label: my-app
  {{- include "operator.labels" . | nindent 4 }}
spec:
  group: test.example.com
  names:
    kind: CephVolume
    listKind: CephVolumeList
    plural: cephvolumes
    singular: cephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.pool
      name: Pool
      type: string
    - description: Storage type
      jsonPath: .status.type
      name: Type
      type: string
    - description: Volume size
      jsonPath: .spec.size
      name: Size
      type: string
    - description: Max number of volume I/O operations per second
      jsonPath: .status.limits.iops
      name: IOPS
      type: string
    - description: true if volume contains latest type,size spec from Ceph
      jsonPath: .status.conditions[?(@.type=="Provided")].status
      name: Provided
      type: string
    - description: true if volume IOPS limits calculated. False indicates error - check
        reason for details
      jsonPath: .status.conditions[?(@.type=="Calculated")].status
      name: Calculated
      type: string
    - description: true if volume IOPS limits applied to volume. False indicates error
        - check reason for details
      jsonPath: .status.conditions[?(@.type=="Limited")].status
      name: Limited
      type: string
    - description: latest resource generation
      jsonPath: .metadata.generation
      name: gen
      type: string
    - description: latest observed generation of Limited condition
      jsonPath: .status.conditions[?(@.type=="Limited")].observedGeneration
      name: Lim-gen
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: CephVolume represents Ceph RBD volume
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: CephVolumeSpec defines the desired state of CephVolume
            properties:
              pool:
                description: Pool - volume pool name
                type: string
              size:
                anyOf:
                - type: integer
                - type: string
                description: Size - volume size
                pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                x-kubernetes-int-or-string: true
            type: object
          status:
            description: CephVolumeStatus defines the observed state of CephVolume
            properties:
              conditions:
                description: 'Conditions represent the latest available observations
                  of an object''s state Known .status.conditions.type are: "Provided".
                  "Calculated", "Limited"'
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    type FooStatus struct{     // Represents the observations of a foo's
                    current state.     // Known .status.conditions.type are: \"Available\",
                    \"Progressing\", and \"Degraded\"     // +patchMergeKey=type     //
                    +patchStrategy=merge     // +listType=map     // +listMapKey=type
                    \    Conditions []metav1.Condition `json:\"conditions,omitempty\"
                    patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                    \n     // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating details
                        about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers of
                        specific condition types may define expected values and meanings
                        for this field, and whether the values are considered a guaranteed
                        API. The value should be a CamelCase string. This field may
                        not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
              limits:
                description: Limits represent calculated IOPS limits
                properties:
                  iops:
                    description: IOPS - desired limit of IO operations per second. See
                      Ceph rbd_qos_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  iopsBurst:
                    description: IOPSBurst - desired burst limit of IO operations. See
                      Ceph rbd_qos_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPS:
                    description: ReadIOPS - desired limit of read operations per second.
                      See Ceph rbd_qos_read_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPSBurst:
                    description: ReadIOPSBurst - desired burst limit of read operations.
                      See Ceph rbd_qos_read_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPS:
                    description: WriteIOPS - desired limit of write operations per second.
                      See Ceph rbd_qos_write_iops_limit property
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPSBurst:
                    description: WriteIOPSBurst - desired burst limit of write operations.
                      See Ceph rbd_qos_write_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                type: object
              type:
                description: Type - volume storage type. See StorageType CRD.
                type: string
            required:
            - conditions
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
0707010000002B000081A400000000000000000000000167C86259000000D6000000000000000000000000000000000000003F00000000helmify-0.4.18/examples/operator/templates/configmap-vars.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "operator.fullname" . }}-configmap-vars
  labels:
  {{- include "operator.labels" . | nindent 4 }}
data:
  VAR4: {{ .Values.configmapVars.var4 | quote }}
0707010000002C000081A400000000000000000000000167C8625900001075000000000000000000000000000000000000003B00000000helmify-0.4.18/examples/operator/templates/deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "operator.fullname" . }}-controller-manager
  labels:
    control-plane: controller-manager
  {{- include "operator.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.controllerManager.replicas }}
  strategy:
    rollingUpdate:
      maxSurge: {{ .Values.controllerManager.strategy.rollingUpdate.maxSurge | quote
        }}
      maxUnavailable: {{ .Values.controllerManager.strategy.rollingUpdate.maxUnavailable
        | quote }}
    type: {{ .Values.controllerManager.strategy.type | quote }}
  selector:
    matchLabels:
      control-plane: controller-manager
    {{- include "operator.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        control-plane: controller-manager
      {{- include "operator.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - args: {{- toYaml .Values.controllerManager.kubeRbacProxy.args | nindent 8 }}
        env:
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag
          | default .Chart.AppVersion }}
        name: kube-rbac-proxy
        ports:
        - containerPort: 8443
          name: https
        resources: {}
      - args: {{- toYaml .Values.controllerManager.manager.args | nindent 8 }}
        command:
        - /manager
        env:
        - name: VAR1
          valueFrom:
            secretKeyRef:
              key: VAR1
              name: {{ include "operator.fullname" . }}-secret-vars
        - name: VAR2
          value: {{ quote .Values.controllerManager.manager.env.var2 }}
        - name: VAR3_MY_ENV
          value: {{ quote .Values.controllerManager.manager.env.var3MyEnv }}
        - name: VAR4
          valueFrom:
            configMapKeyRef:
              key: VAR4
              name: {{ include "operator.fullname" . }}-configmap-vars
        - name: VAR5
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: VAR6
          valueFrom:
            resourceFieldRef:
              divisor: "0"
              resource: limits.cpu
        - name: KUBERNETES_CLUSTER_DOMAIN
          value: {{ quote .Values.kubernetesClusterDomain }}
        image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag
          | default .Chart.AppVersion }}
        imagePullPolicy: {{ .Values.controllerManager.manager.imagePullPolicy }}
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: manager
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10
          }}
        securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext
          | nindent 10 }}
        volumeMounts:
        - mountPath: /controller_manager_config.yaml
          name: manager-config
          subPath: controller_manager_config.yaml
        - mountPath: /my.ca
          name: secret-volume
      imagePullSecrets:
      - name: {{ include "operator.fullname" . }}-secret-registry-credentials
      nodeSelector: {{- toYaml .Values.controllerManager.nodeSelector | nindent 8 }}
      securityContext: {{- toYaml .Values.controllerManager.podSecurityContext | nindent
        8 }}
      serviceAccountName: {{ include "operator.fullname" . }}-controller-manager
      terminationGracePeriodSeconds: 10
      topologySpreadConstraints:
      - matchLabelKeys:
        - app
        - pod-template-hash
        maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
      volumes:
      - configMap:
          name: {{ include "operator.fullname" . }}-manager-config
        name: manager-config
      - name: secret-volume
        secret:
          secretName: {{ include "operator.fullname" . }}-secret-ca
0707010000002D000081A400000000000000000000000167C86259000003EB000000000000000000000000000000000000004500000000helmify-0.4.18/examples/operator/templates/leader-election-rbac.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: {{ include "operator.fullname" . }}-leader-election-role
  labels:
  {{- include "operator.labels" . | nindent 4 }}
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: {{ include "operator.fullname" . }}-leader-election-rolebinding
  labels:
  {{- include "operator.labels" . | nindent 4 }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: '{{ include "operator.fullname" . }}-leader-election-role'
subjects:
- kind: ServiceAccount
  name: '{{ include "operator.fullname" . }}-controller-manager'
  namespace: '{{ .Release.Namespace }}'
0707010000002E000081A400000000000000000000000167C8625900000168000000000000000000000000000000000000004800000000helmify-0.4.18/examples/operator/templates/manager-aggregated-rbac.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ include "operator.fullname" . }}-manager-aggregated-role
  labels:
  {{- include "operator.labels" . | nindent 4 }}
aggregationRule:
  clusterRoleSelectors:
  - matchExpressions:
    - key: app.kubernetes.io/instance
      operator: In
      values:
      - my-operator
rules: []
0707010000002F000081A400000000000000000000000167C8625900000162000000000000000000000000000000000000003F00000000helmify-0.4.18/examples/operator/templates/manager-config.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "operator.fullname" . }}-manager-config
  labels:
  {{- include "operator.labels" . | nindent 4 }}
data:
  controller_manager_config.yaml: {{ .Values.managerConfig.controllerManagerConfigYaml
    | toYaml | indent 1 }}
  dummyconfigmapkey: {{ .Values.managerConfig.dummyconfigmapkey | quote }}
07070100000030000081A400000000000000000000000167C86259000006A6000000000000000000000000000000000000003D00000000helmify-0.4.18/examples/operator/templates/manager-rbac.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ include "operator.fullname" . }}-manager-role
  labels:
  {{- include "operator.labels" . | nindent 4 }}
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
- apiGroups:
  - ""
  resources:
  - pods/exec
  verbs:
  - create
  - get
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - storagetypes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - test.example.com
  resources:
  - storagetypes/status
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: {{ include "operator.fullname" . }}-manager-rolebinding
  labels:
  {{- include "operator.labels" . | nindent 4 }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: '{{ include "operator.fullname" . }}-manager-role'
subjects:
- kind: ServiceAccount
  name: '{{ include "operator.fullname" . }}-controller-manager'
  namespace: '{{ .Release.Namespace }}'
07070100000031000081A400000000000000000000000167C8625900000C8B000000000000000000000000000000000000004700000000helmify-0.4.18/examples/operator/templates/manifestcephvolume-crd.yamlapiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: manifestcephvolumes.test.example.com
  annotations:
    cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "operator.fullname"
      . }}-serving-cert'
  labels:
  {{- include "operator.labels" . | nindent 4 }}
spec:
  conversion:
    strategy: Webhook
    webhook:
      clientConfig:
        service:
          name: '{{ include "operator.fullname" . }}-webhook-service'
          namespace: '{{ .Release.Namespace }}'
          path: /convert
      conversionReviewVersions:
      - v1
  group: test.example.com
  names:
    kind: ManifestCephVolume
    listKind: ManifestCephVolumeList
    plural: manifestcephvolumes
    singular: manifestcephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.poolName
      name: PoolName
      type: string
    - description: Sync interval in seconds
      jsonPath: .spec.interval
      name: Interval
      type: string
    - description: Last update time
      jsonPath: .status.lastUpdate
      name: LastUpdate
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: ManifestCephVolume monitors given ceph pool and manifests containing
          volumes as CephVolume CR
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: ManifestCephVolumeSpec defines the desired state of ManifestCephVolume
            properties:
              interval:
                description: Interval - Ceph pool polling interval
                format: int32
                minimum: 60
                type: integer
              poolName:
                description: PoolName name of Ceph RBD pool to get volumes
                type: string
            required:
            - interval
            type: object
          status:
            description: ManifestCephVolumeStatus defines the observed state of ManifestCephVolume
            properties:
              lastUpdate:
                description: LastUpdate - time of last successful volumes update
                format: date-time
                type: string
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
07070100000032000081A400000000000000000000000167C86259000000F3000000000000000000000000000000000000004400000000helmify-0.4.18/examples/operator/templates/metrics-reader-rbac.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ include "operator.fullname" . }}-metrics-reader
  labels:
  {{- include "operator.labels" . | nindent 4 }}
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
07070100000033000081A400000000000000000000000167C86259000001B8000000000000000000000000000000000000004000000000helmify-0.4.18/examples/operator/templates/metrics-service.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "operator.fullname" . }}-controller-manager-metrics-service
  labels:
    control-plane: controller-manager
  {{- include "operator.labels" . | nindent 4 }}
spec:
  type: {{ .Values.metricsService.type }}
  selector:
    control-plane: controller-manager
    {{- include "operator.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.metricsService.ports | toYaml | nindent 2 }}
07070100000034000081A400000000000000000000000167C862590000031B000000000000000000000000000000000000004F00000000helmify-0.4.18/examples/operator/templates/mutating-webhook-configuration.yamlapiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: {{ include "operator.fullname" . }}-mutating-webhook-configuration
  annotations:
    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "operator.fullname" . }}-serving-cert
  labels:
  {{- include "operator.labels" . | nindent 4 }}
webhooks:
- admissionReviewVersions:
  - v1
  clientConfig:
    service:
      name: '{{ include "operator.fullname" . }}-webhook-service'
      namespace: '{{ .Release.Namespace }}'
      path: /mutate-ceph-example-com-v1-mycluster
  failurePolicy: Fail
  name: mmycluster.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - myclusters
  sideEffects: None
07070100000035000081A400000000000000000000000167C8625900000346000000000000000000000000000000000000003B00000000helmify-0.4.18/examples/operator/templates/proxy-rbac.yamlapiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: {{ include "operator.fullname" . }}-proxy-role
  labels:
  {{- include "operator.labels" . | nindent 4 }}
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - tokenreviews
  verbs:
  - create
- apiGroups:
  - authorization.k8s.io
  resources:
  - subjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: {{ include "operator.fullname" . }}-proxy-rolebinding
  labels:
  {{- include "operator.labels" . | nindent 4 }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: '{{ include "operator.fullname" . }}-proxy-role'
subjects:
- kind: ServiceAccount
  name: '{{ include "operator.fullname" . }}-controller-manager'
  namespace: '{{ .Release.Namespace }}'
07070100000036000081A400000000000000000000000167C8625900000167000000000000000000000000000000000000003800000000helmify-0.4.18/examples/operator/templates/pvc-lim.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: {{ include "operator.fullname" . }}-pvc-lim
  labels:
  {{- include "operator.labels" . | nindent 4 }}
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: {{ .Values.pvc.pvcLim.storageRequest | quote }}
  storageClassName: {{ .Values.pvc.pvcLim.storageClass | quote }}
07070100000037000081A400000000000000000000000167C862590000010C000000000000000000000000000000000000003A00000000helmify-0.4.18/examples/operator/templates/secret-ca.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "operator.fullname" . }}-secret-ca
  labels:
  {{- include "operator.labels" . | nindent 4 }}
data:
  ca.crt: {{ required "secretCa.caCrt is required" .Values.secretCa.caCrt | b64enc
    | quote }}
type: opaque
07070100000038000081A400000000000000000000000167C8625900000179000000000000000000000000000000000000004C00000000helmify-0.4.18/examples/operator/templates/secret-registry-credentials.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "operator.fullname" . }}-secret-registry-credentials
  labels:
  {{- include "operator.labels" . | nindent 4 }}
data:
  .dockerconfigjson: {{ required "secretRegistryCredentials.dockerconfigjson is required"
    .Values.secretRegistryCredentials.dockerconfigjson | b64enc | quote }}
type: kubernetes.io/dockerconfigjson
07070100000039000081A400000000000000000000000167C8625900000170000000000000000000000000000000000000003C00000000helmify-0.4.18/examples/operator/templates/secret-vars.yamlapiVersion: v1
kind: Secret
metadata:
  name: {{ include "operator.fullname" . }}-secret-vars
  labels:
  {{- include "operator.labels" . | nindent 4 }}
data:
  VAR1: {{ required "secretVars.var1 is required" .Values.secretVars.var1 | b64enc
    | quote }}
  VAR2: {{ required "secretVars.var2 is required" .Values.secretVars.var2 | b64enc
    | quote }}
type: opaque
0707010000003A000081A400000000000000000000000167C86259000000C6000000000000000000000000000000000000004200000000helmify-0.4.18/examples/operator/templates/selfsigned-issuer.yamlapiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: {{ include "operator.fullname" . }}-selfsigned-issuer
  labels:
  {{- include "operator.labels" . | nindent 4 }}
spec:
  selfSigned: {}
0707010000003B000081A400000000000000000000000167C862590000010A000000000000000000000000000000000000003F00000000helmify-0.4.18/examples/operator/templates/serviceaccount.yamlapiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "operator.fullname" . }}-controller-manager
  labels:
  {{- include "operator.labels" . | nindent 4 }}
  annotations:
    {{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }}
0707010000003C000081A400000000000000000000000167C862590000021B000000000000000000000000000000000000003D00000000helmify-0.4.18/examples/operator/templates/serving-cert.yamlapiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: {{ include "operator.fullname" . }}-serving-cert
  labels:
  {{- include "operator.labels" . | nindent 4 }}
spec:
  dnsNames:
  - '{{ include "operator.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc'
  - '{{ include "operator.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc.{{
    .Values.kubernetesClusterDomain }}'
  issuerRef:
    kind: Issuer
    name: '{{ include "operator.fullname" . }}-selfsigned-issuer'
  secretName: webhook-server-cert
0707010000003D000081A400000000000000000000000167C8625900000330000000000000000000000000000000000000005100000000helmify-0.4.18/examples/operator/templates/validating-webhook-configuration.yamlapiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: {{ include "operator.fullname" . }}-validating-webhook-configuration
  annotations:
    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "operator.fullname" . }}-serving-cert
  labels:
  {{- include "operator.labels" . | nindent 4 }}
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: '{{ include "operator.fullname" . }}-webhook-service'
      namespace: '{{ .Release.Namespace }}'
      path: /validate-ceph-example-com-v1alpha1-volume
  failurePolicy: Fail
  name: vvolume.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1alpha1
    operations:
    - CREATE
    - UPDATE
    resources:
    - volumes
  sideEffects: None
0707010000003E000081A400000000000000000000000167C862590000017F000000000000000000000000000000000000004000000000helmify-0.4.18/examples/operator/templates/webhook-service.yamlapiVersion: v1
kind: Service
metadata:
  name: {{ include "operator.fullname" . }}-webhook-service
  labels:
  {{- include "operator.labels" . | nindent 4 }}
spec:
  type: {{ .Values.webhookService.type }}
  selector:
    control-plane: controller-manager
    {{- include "operator.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.webhookService.ports | toYaml | nindent 2 }}
0707010000003F000081A400000000000000000000000167C8625900000830000000000000000000000000000000000000002D00000000helmify-0.4.18/examples/operator/values.yamlconfigmapVars:
  var4: value for var4
controllerManager:
  kubeRbacProxy:
    args:
    - --secure-listen-address=0.0.0.0:8443
    - --upstream=http://127.0.0.1:8080/
    - --logtostderr=true
    - --v=10
    image:
      repository: gcr.io/kubebuilder/kube-rbac-proxy
      tag: v0.8.0
  manager:
    args:
    - --health-probe-bind-address=:8081
    - --metrics-bind-address=127.0.0.1:8080
    - --leader-elect
    containerSecurityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      privileged: false
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 65532
      seccompProfile:
        type: RuntimeDefault
    env:
      var2: ciao
      var3MyEnv: ciao
    image:
      repository: controller
      tag: latest
    imagePullPolicy: Always
    resources:
      limits:
        cpu: 100m
        memory: 30Mi
      requests:
        cpu: 100m
        memory: 20Mi
  nodeSelector:
    region: east
    type: user-node
  podSecurityContext:
    runAsNonRoot: true
  replicas: 1
  serviceAccount:
    annotations:
      k8s.acme.org/some-meta-data: ACME Inc.
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
kubernetesClusterDomain: cluster.local
managerConfig:
  controllerManagerConfigYaml: |-
    apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
    kind: ControllerManagerConfig
    health:
      healthProbeBindAddress: :8081
    metrics:
      bindAddress: 127.0.0.1:8080
    webhook:
      port: 9443
    leaderElection:
      leaderElect: true
      resourceName: 3a2e09e9.example.com
    rook:
      namespace: rook-ceph
      toolboxPodLabel: rook-ceph-tools
  dummyconfigmapkey: dummyconfigmapvalue
metricsService:
  ports:
  - name: https
    port: 8443
    targetPort: https
  type: ClusterIP
pvc:
  pvcLim:
    storageClass: cust1-mypool-lim
    storageRequest: 2Gi
secretCa:
  caCrt: ""
secretRegistryCredentials:
  dockerconfigjson: ""
secretVars:
  var1: ""
  var2: ""
webhookService:
  ports:
  - port: 443
    targetPort: 9443
  type: ClusterIP
07070100000040000081A400000000000000000000000167C8625900001982000000000000000000000000000000000000001600000000helmify-0.4.18/go.modmodule github.com/arttor/helmify

go 1.21

require (
	dario.cat/mergo v1.0.0
	github.com/iancoleman/strcase v0.2.0
	github.com/sirupsen/logrus v1.9.0
	github.com/stretchr/testify v1.8.1
	helm.sh/helm/v3 v3.11.2
	k8s.io/api v0.26.2
	k8s.io/apiextensions-apiserver v0.26.2
	k8s.io/apimachinery v0.26.2
	sigs.k8s.io/yaml v1.3.0
)

require (
	github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
	github.com/BurntSushi/toml v1.2.1 // indirect
	github.com/MakeNowJust/heredoc v1.0.0 // indirect
	github.com/Masterminds/goutils v1.1.1 // indirect
	github.com/Masterminds/semver/v3 v3.2.0 // indirect
	github.com/Masterminds/sprig/v3 v3.2.3 // indirect
	github.com/Masterminds/squirrel v1.5.3 // indirect
	github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/cespare/xxhash/v2 v2.2.0 // indirect
	github.com/chai2010/gettext-go v1.0.2 // indirect
	github.com/containerd/containerd v1.6.15 // indirect
	github.com/cyphar/filepath-securejoin v0.2.3 // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/docker/cli v20.10.21+incompatible // indirect
	github.com/docker/distribution v2.8.1+incompatible // indirect
	github.com/docker/docker v20.10.21+incompatible // indirect
	github.com/docker/docker-credential-helpers v0.7.0 // indirect
	github.com/docker/go-connections v0.4.0 // indirect
	github.com/docker/go-metrics v0.0.1 // indirect
	github.com/docker/go-units v0.4.0 // indirect
	github.com/emicklei/go-restful/v3 v3.9.0 // indirect
	github.com/evanphx/json-patch v5.6.0+incompatible // indirect
	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
	github.com/fatih/color v1.13.0 // indirect
	github.com/go-errors/errors v1.0.1 // indirect
	github.com/go-gorp/gorp/v3 v3.0.5 // indirect
	github.com/go-logr/logr v1.2.3 // indirect
	github.com/go-openapi/jsonpointer v0.19.6 // indirect
	github.com/go-openapi/jsonreference v0.20.1 // indirect
	github.com/go-openapi/swag v0.22.3 // indirect
	github.com/gobwas/glob v0.2.3 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang/protobuf v1.5.3 // indirect
	github.com/google/btree v1.0.1 // indirect
	github.com/google/gnostic v0.5.7-v3refs // indirect
	github.com/google/go-cmp v0.5.9 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
	github.com/google/uuid v1.3.0 // indirect
	github.com/gorilla/mux v1.8.0 // indirect
	github.com/gosuri/uitable v0.0.4 // indirect
	github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
	github.com/huandu/xstrings v1.4.0 // indirect
	github.com/imdario/mergo v0.3.16 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/jmoiron/sqlx v1.3.5 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/klauspost/compress v1.11.13 // indirect
	github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
	github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
	github.com/lib/pq v1.10.7 // indirect
	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
	github.com/mailru/easyjson v0.7.7 // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.17 // indirect
	github.com/mattn/go-runewidth v0.0.9 // indirect
	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
	github.com/mitchellh/copystructure v1.2.0 // indirect
	github.com/mitchellh/go-wordwrap v1.0.0 // indirect
	github.com/mitchellh/reflectwalk v1.0.2 // indirect
	github.com/moby/locker v1.0.1 // indirect
	github.com/moby/spdystream v0.2.0 // indirect
	github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
	github.com/morikuni/aec v1.0.0 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/opencontainers/go-digest v1.0.0 // indirect
	github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/prometheus/client_golang v1.16.0 // indirect
	github.com/prometheus/client_model v0.4.0 // indirect
	github.com/prometheus/common v0.44.0 // indirect
	github.com/prometheus/procfs v0.10.1 // indirect
	github.com/rubenv/sql-migrate v1.3.1 // indirect
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
	github.com/shopspring/decimal v1.3.1 // indirect
	github.com/spf13/cast v1.5.0 // indirect
	github.com/spf13/cobra v1.7.0 // indirect
	github.com/spf13/pflag v1.0.5 // indirect
	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
	github.com/xlab/treeprint v1.1.0 // indirect
	go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
	golang.org/x/crypto v0.13.0 // indirect
	golang.org/x/net v0.15.0 // indirect
	golang.org/x/oauth2 v0.8.0 // indirect
	golang.org/x/sync v0.2.0 // indirect
	golang.org/x/sys v0.12.0 // indirect
	golang.org/x/term v0.12.0 // indirect
	golang.org/x/text v0.13.0 // indirect
	golang.org/x/time v0.3.0 // indirect
	google.golang.org/appengine v1.6.7 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
	google.golang.org/grpc v1.54.0 // indirect
	google.golang.org/protobuf v1.30.0 // indirect
	gopkg.in/inf.v0 v0.9.1 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
	k8s.io/apiserver v0.26.2 // indirect
	k8s.io/cli-runtime v0.26.0 // indirect
	k8s.io/client-go v0.26.2 // indirect
	k8s.io/component-base v0.26.2 // indirect
	k8s.io/klog/v2 v2.90.1 // indirect
	k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
	k8s.io/kubectl v0.26.0 // indirect
	k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 // indirect
	oras.land/oras-go v1.2.2 // indirect
	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
	sigs.k8s.io/kustomize/api v0.12.1 // indirect
	sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
07070100000041000081A400000000000000000000000167C8625900019CD2000000000000000000000000000000000000001600000000helmify-0.4.18/go.sumcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/hcsshim v0.9.6 h1:VwnDOgLeoi2du6dAznfmspNqTiwczvjv4K7NxuY9jsY=
github.com/Microsoft/hcsshim v0.9.6/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
github.com/containerd/containerd v1.6.15 h1:4wWexxzLNHNE46aIETc6ge4TofO550v+BlLoANrbses=
github.com/containerd/containerd v1.6.15/go.mod h1:U2NnBPIhzJDm59xF7xB2MMHnKtggpZ+phKg8o2TKj2c=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU=
github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog=
github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gorp/gorp/v3 v3.0.5 h1:PUjzYdYu3HBOh8LE+UUmRG2P0IRDak9XMeGNvaeq4Ow=
github.com/go-gorp/gorp/v3 v3.0.5/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nelsam/hel/v2 v2.3.2/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w=
github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/poy/onpar v0.0.0-20200406201722-06f95a1c68e8/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA=
github.com/rubenv/sql-migrate v1.3.1/go.mod h1:YzG/Vh82CwyhTFXy+Mf5ahAiiEOpAlHurg+23VEzcsk=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221013171732-95e765b1cc43/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200313205530-4303120df7d8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
helm.sh/helm/v3 v3.11.2 h1:P3cLaFxfoxaGLGJVnoPrhf1j86LC5EDINSpYSpMUkkA=
helm.sh/helm/v3 v3.11.2/go.mod h1:Hw+09mfpDiRRKAgAIZlFkPSeOkvv7Acl5McBvQyNPVw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ=
k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU=
k8s.io/apiextensions-apiserver v0.26.2 h1:/yTG2B9jGY2Q70iGskMf41qTLhL9XeNN2KhI0uDgwko=
k8s.io/apiextensions-apiserver v0.26.2/go.mod h1:Y7UPgch8nph8mGCuVk0SK83LnS8Esf3n6fUBgew8SH8=
k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ=
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
k8s.io/apiserver v0.26.2 h1:Pk8lmX4G14hYqJd1poHGC08G03nIHVqdJMR0SD3IH3o=
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8=
k8s.io/cli-runtime v0.26.0 h1:aQHa1SyUhpqxAw1fY21x2z2OS5RLtMJOCj7tN4oq8mw=
k8s.io/cli-runtime v0.26.0/go.mod h1:o+4KmwHzO/UK0wepE1qpRk6l3o60/txUZ1fEXWGIKTY=
k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI=
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU=
k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI=
k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs=
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/kubectl v0.26.0 h1:xmrzoKR9CyNdzxBmXV7jW9Ln8WMrwRK6hGbbf69o4T0=
k8s.io/kubectl v0.26.0/go.mod h1:eInP0b+U9XUJWSYeU9XZnTA+cVYuWyl3iYPGtru0qhQ=
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 h1:xMMXJlJbsU8w3V5N2FLDQ8YgU8s1EoULdbQBcAeNJkY=
k8s.io/utils v0.0.0-20230313181309-38a27ef9d749/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
oras.land/oras-go v1.2.2 h1:0E9tOHUfrNH7TCDk5KU0jVBEzCqbfdyuVfGmJ7ZeRPE=
oras.land/oras-go v1.2.2/go.mod h1:Apa81sKoZPpP7CDciE006tSZ0x3Q3+dOoBcMZ/aNxvw=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
07070100000042000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001800000000helmify-0.4.18/internal07070100000043000081A400000000000000000000000167C86259000002C5000000000000000000000000000000000000002600000000helmify-0.4.18/internal/test_utils.gopackage internal

import (
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
)

const (
	nsYaml = `apiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-system`
	TestNsName = "my-operator-system"
)

// TestNs k8s namespace object example.
var TestNs = GenerateObj(nsYaml)

// GenerateObj generates unstructured form yaml string.
func GenerateObj(objYaml string) *unstructured.Unstructured {
	obj := unstructured.Unstructured{}
	dec := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
	_, _, err := dec.Decode([]byte(objYaml), nil, &obj)
	if err != nil {
		panic(err)
	}
	return &obj
}
07070100000044000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001300000000helmify-0.4.18/pkg07070100000045000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001700000000helmify-0.4.18/pkg/app07070100000046000081A400000000000000000000000167C8625900000A0F000000000000000000000000000000000000001E00000000helmify-0.4.18/pkg/app/app.gopackage app

import (
	"context"
	"io"
	"os"
	"os/signal"
	"syscall"

	"github.com/arttor/helmify/pkg/file"
	"github.com/arttor/helmify/pkg/processor/job"
	"github.com/arttor/helmify/pkg/processor/poddisruptionbudget"
	"github.com/arttor/helmify/pkg/processor/statefulset"

	"github.com/sirupsen/logrus"

	"github.com/arttor/helmify/pkg/config"
	"github.com/arttor/helmify/pkg/decoder"
	"github.com/arttor/helmify/pkg/helm"
	"github.com/arttor/helmify/pkg/processor"
	"github.com/arttor/helmify/pkg/processor/configmap"
	"github.com/arttor/helmify/pkg/processor/crd"
	"github.com/arttor/helmify/pkg/processor/daemonset"
	"github.com/arttor/helmify/pkg/processor/deployment"
	"github.com/arttor/helmify/pkg/processor/rbac"
	"github.com/arttor/helmify/pkg/processor/secret"
	"github.com/arttor/helmify/pkg/processor/service"
	"github.com/arttor/helmify/pkg/processor/storage"
	"github.com/arttor/helmify/pkg/processor/webhook"
)

// Start - application entrypoint for processing input to a Helm chart.
func Start(stdin io.Reader, config config.Config) error {
	err := config.Validate()
	if err != nil {
		return err
	}
	setLogLevel(config)
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	done := make(chan os.Signal, 1)
	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-done
		logrus.Debug("Received termination, signaling shutdown")
		cancelFunc()
	}()
	appCtx := New(config, helm.NewOutput())
	appCtx = appCtx.WithProcessors(
		configmap.New(),
		crd.New(),
		daemonset.New(),
		deployment.New(),
		statefulset.New(),
		storage.New(),
		service.New(),
		service.NewIngress(),
		rbac.ClusterRoleBinding(),
		rbac.Role(),
		rbac.RoleBinding(),
		rbac.ServiceAccount(),
		secret.New(),
		webhook.Issuer(),
		webhook.Certificate(),
		webhook.ValidatingWebhook(),
		webhook.MutatingWebhook(),
		job.NewCron(),
		job.NewJob(),
		poddisruptionbudget.New(),
	).WithDefaultProcessor(processor.Default())
	if len(config.Files) != 0 {
		file.Walk(config.Files, config.FilesRecursively, func(filename string, fileReader io.Reader) {
			objects := decoder.Decode(ctx.Done(), fileReader)
			for obj := range objects {
				appCtx.Add(obj, filename)
			}
		})
	} else {
		objects := decoder.Decode(ctx.Done(), stdin)
		for obj := range objects {
			appCtx.Add(obj, "")
		}
	}

	return appCtx.CreateHelm(ctx.Done())
}

func setLogLevel(config config.Config) {
	logrus.SetLevel(logrus.ErrorLevel)
	if config.Verbose {
		logrus.SetLevel(logrus.InfoLevel)
	}
	if config.VeryVerbose {
		logrus.SetLevel(logrus.DebugLevel)
	}
}
07070100000047000081A400000000000000000000000167C8625900000527000000000000000000000000000000000000002700000000helmify-0.4.18/pkg/app/app_e2e_test.gopackage app

import (
	"bufio"
	"os"
	"testing"

	"github.com/arttor/helmify/pkg/config"
	"github.com/stretchr/testify/assert"
	"helm.sh/helm/v3/pkg/action"
)

const (
	operatorChartName = "test-operator"
	appChartName      = "test-app"
)

func TestOperator(t *testing.T) {
	file, err := os.Open("../../test_data/k8s-operator-kustomize.output")
	assert.NoError(t, err)

	objects := bufio.NewReader(file)
	err = Start(objects, config.Config{ChartName: operatorChartName})
	assert.NoError(t, err)

	t.Cleanup(func() {
		err = os.RemoveAll(operatorChartName)
		assert.NoError(t, err)
	})

	helmLint := action.NewLint()
	helmLint.Strict = true
	helmLint.Namespace = "test-ns"
	result := helmLint.Run([]string{operatorChartName}, nil)
	for _, err = range result.Errors {
		assert.NoError(t, err)
	}
}

func TestApp(t *testing.T) {
	file, err := os.Open("../../test_data/sample-app.yaml")
	assert.NoError(t, err)

	objects := bufio.NewReader(file)
	err = Start(objects, config.Config{ChartName: appChartName})
	assert.NoError(t, err)

	t.Cleanup(func() {
		err = os.RemoveAll(appChartName)
		assert.NoError(t, err)
	})

	helmLint := action.NewLint()
	helmLint.Strict = true
	helmLint.Namespace = "test-ns"
	result := helmLint.Run([]string{appChartName}, nil)
	for _, err = range result.Errors {
		assert.NoError(t, err)
	}
}
07070100000048000081A400000000000000000000000167C8625900000C59000000000000000000000000000000000000002200000000helmify-0.4.18/pkg/app/context.gopackage app

import (
	"github.com/arttor/helmify/pkg/config"
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/metadata"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// appContext helm processing context. Stores processed objects.
type appContext struct {
	processors       []helmify.Processor
	defaultProcessor helmify.Processor
	output           helmify.Output
	config           config.Config
	appMeta          *metadata.Service
	objects          []*unstructured.Unstructured
	fileNames        []string
}

// New returns context with config set.
func New(config config.Config, output helmify.Output) *appContext {
	return &appContext{
		config:  config,
		appMeta: metadata.New(config),
		output:  output,
	}
}

// WithProcessors  add processors to the context and returns it.
func (c *appContext) WithProcessors(processors ...helmify.Processor) *appContext {
	c.processors = append(c.processors, processors...)
	return c
}

// WithDefaultProcessor  add defaultProcessor for unknown resources to the context and returns it.
func (c *appContext) WithDefaultProcessor(processor helmify.Processor) *appContext {
	c.defaultProcessor = processor
	return c
}

// Add k8s object to app context.
func (c *appContext) Add(obj *unstructured.Unstructured, filename string) {
	// we need to add all objects before start processing only to define app metadata.
	c.appMeta.Load(obj)
	c.objects = append(c.objects, obj)
	c.fileNames = append(c.fileNames, filename)
}

// CreateHelm creates helm chart from context k8s objects.
func (c *appContext) CreateHelm(stop <-chan struct{}) error {
	logrus.WithFields(logrus.Fields{
		"ChartName": c.appMeta.ChartName(),
		"Namespace": c.appMeta.Namespace(),
	}).Info("creating a chart")
	var templates []helmify.Template
	var filenames []string
	for i, obj := range c.objects {
		template, err := c.process(obj)
		if err != nil {
			return err
		}
		if template != nil {
			templates = append(templates, template)
			filename := template.Filename()
			if c.fileNames[i] != "" {
				filename = c.fileNames[i]
			}
			filenames = append(filenames, filename)
		}
		select {
		case <-stop:
			return nil
		default:
		}
	}
	return c.output.Create(c.config.ChartDir, c.config.ChartName, c.config.Crd, c.config.CertManagerAsSubchart, c.config.CertManagerVersion, c.config.CertManagerInstallCRD, templates, filenames)
}

func (c *appContext) process(obj *unstructured.Unstructured) (helmify.Template, error) {
	for _, p := range c.processors {
		if processed, result, err := p.Process(c.appMeta, obj); processed {
			if err != nil {
				return nil, err
			}
			logrus.WithFields(logrus.Fields{
				"ApiVersion": obj.GetAPIVersion(),
				"Kind":       obj.GetKind(),
				"Name":       obj.GetName(),
			}).Debug("processed")
			return result, nil
		}
	}
	if c.defaultProcessor == nil {
		logrus.WithFields(logrus.Fields{
			"ApiVersion": obj.GetAPIVersion(),
			"Kind":       obj.GetKind(),
			"Name":       obj.GetName(),
		}).Warn("Skipping: no suitable processor for resource.")
		return nil, nil
	}
	_, t, err := c.defaultProcessor.Process(c.appMeta, obj)
	return t, err
}
07070100000049000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001B00000000helmify-0.4.18/pkg/cluster0707010000004A000081A400000000000000000000000167C8625900000094000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/cluster/domain.gopackage cluster

const (
	DefaultDomain = "cluster.local"
	DomainKey     = "kubernetesClusterDomain"
	DomainEnv     = "KUBERNETES_CLUSTER_DOMAIN"
)
0707010000004B000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001A00000000helmify-0.4.18/pkg/config0707010000004C000081A400000000000000000000000167C86259000007F8000000000000000000000000000000000000002400000000helmify-0.4.18/pkg/config/config.gopackage config

import (
	"fmt"

	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/util/validation"
)

// defaultChartName - default name for a helm chart directory.
const defaultChartName = "chart"

// Config for Helmify application.
type Config struct {
	// ChartName name of the Helm chart and its base directory where Chart.yaml is located.
	ChartName string
	// ChartDir - optional path to chart dir. Full chart path will be: ChartDir/ChartName/Chart.yaml.
	ChartDir string
	// Verbose set true to see WARN and INFO logs.
	Verbose bool
	// VeryVerbose set true to see WARN, INFO, and DEBUG logs.
	VeryVerbose bool
	// crd-dir set true to enable crd folder.
	Crd bool
	// ImagePullSecrets flag
	ImagePullSecrets bool
	// GenerateDefaults enables the generation of empty values placeholders for common customization options of helm chart
	// current generated values: tolerances, node selectors, topology constraints
	GenerateDefaults bool
	// CertManagerAsSubchart enables the generation of a subchart for cert-manager
	CertManagerAsSubchart bool
	// CertManagerVersion sets cert-manager version in dependency
	CertManagerVersion string
	// CertManagerVersion enables installation of cert-manager CRD
	CertManagerInstallCRD bool
	// Files - directories or files with k8s manifests
	Files []string
	// FilesRecursively read Files recursively
	FilesRecursively bool
	// OriginalName retains Kubernetes resource's original name
	OriginalName bool
	// PreserveNs retains the namespaces on the Kubernetes manifests
	PreserveNs bool
	// AddWebhookOption enables the generation of a webhook option in values.yamlß
	AddWebhookOption bool
}

func (c *Config) Validate() error {
	if c.ChartName == "" {
		logrus.Infof("Chart name is not set. Using default name '%s", defaultChartName)
		c.ChartName = defaultChartName
	}
	err := validation.IsDNS1123Subdomain(c.ChartName)
	if err != nil {
		for _, e := range err {
			logrus.Errorf("Invalid chart name %s", e)
		}
		return fmt.Errorf("invalid chart name %s", c.ChartName)
	}
	return nil
}
0707010000004D000081A400000000000000000000000167C8625900000535000000000000000000000000000000000000002900000000helmify-0.4.18/pkg/config/config_test.gopackage config

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestConfig_Validate(t *testing.T) {
	type fields struct {
		ChartName   string
		Verbose     bool
		VeryVerbose bool
	}
	tests := []struct {
		name    string
		fields  fields
		wantErr bool
	}{
		{name: "valid", fields: fields{ChartName: ""}, wantErr: false},
		{name: "valid", fields: fields{ChartName: "my.chart123"}, wantErr: false},
		{name: "valid", fields: fields{ChartName: "my-chart123"}, wantErr: false},
		{name: "invalid", fields: fields{ChartName: "my_chart123"}, wantErr: true},
		{name: "invalid", fields: fields{ChartName: "my char123t"}, wantErr: true},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := &Config{
				ChartName:   tt.fields.ChartName,
				Verbose:     tt.fields.Verbose,
				VeryVerbose: tt.fields.VeryVerbose,
			}
			if err := c.Validate(); (err != nil) != tt.wantErr {
				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
	t.Run("chart name not set", func(t *testing.T) {
		c := &Config{}
		err := c.Validate()
		assert.NoError(t, err)
		assert.Equal(t, defaultChartName, c.ChartName)
	})
	t.Run("chart name set", func(t *testing.T) {
		c := &Config{ChartName: "test"}
		err := c.Validate()
		assert.NoError(t, err)
		assert.Equal(t, "test", c.ChartName)
	})
}
0707010000004E000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001B00000000helmify-0.4.18/pkg/decoder0707010000004F000081A400000000000000000000000167C8625900000782000000000000000000000000000000000000002600000000helmify-0.4.18/pkg/decoder/decoder.gopackage decoder

import (
	"errors"
	"io"

	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/serializer/yaml"
	yamlutil "k8s.io/apimachinery/pkg/util/yaml"
)

const (
	yamlDecoderBufferSize          = 100
	decoderResultChannelBufferSize = 1
)

// Decode - reads bytes stream of k8s yaml manifests and decodes it to k8s unstructured objects.
// Non-blocking function. Sends results into buffered channel. Closes channel on io.EOF.
func Decode(stop <-chan struct{}, reader io.Reader) <-chan *unstructured.Unstructured {
	decoder := yamlutil.NewYAMLOrJSONDecoder(reader, yamlDecoderBufferSize)
	res := make(chan *unstructured.Unstructured, decoderResultChannelBufferSize)
	go func() {
		defer close(res)
		logrus.Debug("Start processing...")
		for {
			select {
			case <-stop:
				logrus.Debug("Exiting: received stop signal")
				return
			default:
			}
			var rawObj runtime.RawExtension
			err := decoder.Decode(&rawObj)
			if errors.Is(err, io.EOF) {
				logrus.Debug("EOF received. Finishing input objects decoding.")
				return
			}
			if err != nil {
				logrus.WithError(err).Error("unable to decode yaml from input")
				continue
			}
			obj, _, err := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme).Decode(rawObj.Raw, nil, nil)
			if err != nil {
				logrus.WithError(err).Error("unable to decode yaml")
				continue
			}
			unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
			if err != nil {
				logrus.WithError(err).Error("unable to map yaml to k8s unstructured")
				continue
			}
			object := &unstructured.Unstructured{Object: unstructuredMap}
			logrus.WithFields(logrus.Fields{
				"ApiVersion": object.GetAPIVersion(),
				"Kind":       object.GetKind(),
				"Name":       object.GetName(),
			}).Debug("decoded")
			res <- object
		}
	}()
	return res
}
07070100000050000081A400000000000000000000000167C86259000006BC000000000000000000000000000000000000002B00000000helmify-0.4.18/pkg/decoder/decoder_test.gopackage decoder

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
)

const (
	validObjects2 = `apiVersion: v1
kind: Service
metadata:
  name: my-operator-webhook-service
  namespace: my-operator-system
spec:
  ports:
  - port: 443
    targetPort: 9443
  selector:
    control-plane: controller-manager
---
apiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-system
`
	validObjects2withInvalid = `ajrcmq84xpru038um9q8
wqprux934ur8wcnqwp8urxqwrxuqweruncw
---
apiVersion: v1
kind: Service
metadata:
  name: my-operator-webhook-service
  namespace: my-operator-system
spec:
  ports:
  - port: 443
    targetPort: 9443
  selector:
    control-plane: controller-manager
---
---
---
8umx9284ru 82q983y49q
q 3408tuqw8e
q 49tuqw[fa iwfaowoewihfe4hf
---
apiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-system
---
apiVersion: v1
metadata:
  labels:
`
	validObjects0 = `---
---
---
`
)

func TestDecodeOk(t *testing.T) {
	reader := strings.NewReader(validObjects2)
	stop := make(chan struct{})
	objects := Decode(stop, reader)
	i := 0
	for range objects {
		i++
	}
	assert.Equal(t, 2, i, "decoded two objects")
}

func TestDecodeEmptyObj(t *testing.T) {
	reader := strings.NewReader(validObjects0)
	stop := make(chan struct{})
	objects := Decode(stop, reader)
	i := 0
	for range objects {
		i++
	}
	assert.Equal(t, 0, i, "decoded none objects")
}

func TestDecodeInvalidObj(t *testing.T) {
	reader := strings.NewReader(validObjects2withInvalid)
	stop := make(chan struct{})
	objects := Decode(stop, reader)
	i := 0
	for range objects {
		i++
	}
	assert.Equal(t, 2, i, "decoded 2 valid objects")
}
07070100000051000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001800000000helmify-0.4.18/pkg/file07070100000052000081A400000000000000000000000167C862590000079A000000000000000000000000000000000000002200000000helmify-0.4.18/pkg/file/reader.gopackage file

import (
	"github.com/sirupsen/logrus"
	"io"
	"io/fs"
	"os"
	"path/filepath"
)

func Walk(paths []string, recursively bool, walkFunc func(filename string, r io.Reader)) {

	for _, path := range paths {
		info, err := os.Stat(path)
		if err != nil {
			logrus.Warnf("no such file or directory %q: %v", path, err)
			continue
		}
		// handle single file file:
		if !info.IsDir() {
			file, err := os.Open(path)
			if err != nil {
				logrus.Warnf("unable to open file %q: %v", file.Name(), err)
				continue
			}
			walkFunc(info.Name(), file)
			err = file.Close()
			if err != nil {
				logrus.Warnf("unable to close file %q: %v", file.Name(), err)
			}
			continue
		}
		// handle directory non-recursively:
		if !recursively {
			dir, err := os.Open(path)
			if err != nil {
				logrus.Warnf("unable to open directory %q: %v", dir.Name(), err)
				continue
			}
			files, err := dir.ReadDir(0)
			if err != nil {
				logrus.Warnf("unable to read directory %q: %v", dir.Name(), err)
				continue
			}
			for _, f := range files {
				if f.IsDir() {
					continue
				}
				file, err := os.Open(filepath.Join(path, f.Name()))
				if err != nil {
					logrus.Warnf("unable to open file %q: %v", file.Name(), err)
					continue
				}
				walkFunc(f.Name(), file)
				err = file.Close()
				if err != nil {
					logrus.Warnf("unable to close file %q: %v", file.Name(), err)
				}
				continue
			}
			continue
		}
		// handle directory recursively:
		err = filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
			if err != nil {
				return err
			}
			if d.IsDir() {
				return nil
			}
			file, err := os.Open(path)
			if err != nil {
				return err
			}
			walkFunc(d.Name(), file)
			err = file.Close()
			if err != nil {
				logrus.Warnf("unable to close file %q: %v", file.Name(), err)
			}
			return nil
		})
		if err != nil {
			logrus.Warnf("unable to open %q: %v", info.Name(), err)
			continue
		}
	}
}
07070100000053000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001A00000000helmify-0.4.18/pkg/format07070100000054000081A400000000000000000000000167C8625900000265000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/format/fix_quotes.gopackage format

import (
	"strings"
)

// FixUnterminatedQuotes check for Unterminated Quotes in helm templated strings
// See https://github.com/arttor/helmify/issues/12
func FixUnterminatedQuotes(in string) string {
	sb := strings.Builder{}
	hasUntermQuotes := false
	lines := strings.Split(in, "\n")
	for i, line := range lines {
		if hasUntermQuotes {
			line = " " + strings.TrimSpace(line)
			hasUntermQuotes = false
		} else {
			hasUntermQuotes = strings.Count(line, "\"")%2 != 0
		}
		sb.WriteString(line)
		if !hasUntermQuotes && i != len(lines)-1 {
			sb.WriteString("\n")
		}
	}
	return sb.String()
}
07070100000055000081A400000000000000000000000167C8625900000703000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/format/fix_quotes_test.gopackage format

import "testing"

func TestFixUnterminatedQuotes(t *testing.T) {
	tests := []struct {
		name string
		in   string
		want string
	}{
		{
			name: "remove line break for unterminated quotes",
			in: `apiVersion: v1
kind: Secret
metadata:
  name: {{ include "app.fullname" . }}-my-secret-vars
  labels:
  {{- include "app.labels" . | nindent 4 }}
data:
  ELASTIC_FOOBAR_HUNTER123_MEOWTOWN_VERIFY: {{ required "mySecretVars.elasticFoobarHunter123MeowtownVerify
    is required" .Values.mySecretVars.elasticFoobarHunter123MeowtownVerify | b64enc
    | quote }}
  VAR1: {{ required "mySecretVars.var1 is required" .Values.mySecretVars.var1 | b64enc
    | quote }}
  VAR2: {{ required "mySecretVars.var2 is required" .Values.mySecretVars.var2 | b64enc
    | quote }}
stringData:
  str: {{ required "mySecretVars.str is required" .Values.mySecretVars.str | quote
    }}
type: opaque`,
			want: `apiVersion: v1
kind: Secret
metadata:
  name: {{ include "app.fullname" . }}-my-secret-vars
  labels:
  {{- include "app.labels" . | nindent 4 }}
data:
  ELASTIC_FOOBAR_HUNTER123_MEOWTOWN_VERIFY: {{ required "mySecretVars.elasticFoobarHunter123MeowtownVerify is required" .Values.mySecretVars.elasticFoobarHunter123MeowtownVerify | b64enc
    | quote }}
  VAR1: {{ required "mySecretVars.var1 is required" .Values.mySecretVars.var1 | b64enc
    | quote }}
  VAR2: {{ required "mySecretVars.var2 is required" .Values.mySecretVars.var2 | b64enc
    | quote }}
stringData:
  str: {{ required "mySecretVars.str is required" .Values.mySecretVars.str | quote
    }}
type: opaque`,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := FixUnterminatedQuotes(tt.in); got != tt.want {
				t.Errorf("FixUnterminatedQuotes() = %v, want %v", got, tt.want)
			}
		})
	}
}
07070100000056000081A400000000000000000000000167C86259000000C4000000000000000000000000000000000000003200000000helmify-0.4.18/pkg/format/trailing_whitespaces.gopackage format

import "regexp"

var removeWhitespace = regexp.MustCompile(`(\s+)(\n|$)`)

func RemoveTrailingWhitespaces(in string) string {
	return removeWhitespace.ReplaceAllString(in, "$2")
}
07070100000057000081A400000000000000000000000167C862590000027A000000000000000000000000000000000000003700000000helmify-0.4.18/pkg/format/trailing_whitespaces_test.gopackage format

import "testing"

func TestRemoveTrailingWhitespaces(t *testing.T) {
	tests := []struct {
		name string
		in   string
		want string
	}{
		{
			name: "",
			in:   `abc   `,
			want: `abc`,
		},
		{
			name: "",
			in: `abc   
edf`,
			want: `abc
edf`,
		},
		{
			name: "",
			in: `abc   
edf   `,
			want: `abc
edf`,
		},
		{
			name: "",
			in: `abc   .
edf   .`,
			want: `abc   .
edf   .`,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := RemoveTrailingWhitespaces(tt.in); got != tt.want {
				t.Errorf("RemoveTrailingWhitespaces() = %v, want %v", got, tt.want)
			}
		})
	}
}
07070100000058000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001800000000helmify-0.4.18/pkg/helm07070100000059000081A400000000000000000000000167C8625900000FB0000000000000000000000000000000000000002100000000helmify-0.4.18/pkg/helm/chart.gopackage helm

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/arttor/helmify/pkg/cluster"
	"github.com/arttor/helmify/pkg/helmify"

	"github.com/sirupsen/logrus"

	"sigs.k8s.io/yaml"
)

// NewOutput creates interface to dump processed input to filesystem in Helm chart format.
func NewOutput() helmify.Output {
	return &output{}
}

type output struct{}

// Create a helm chart in the current directory:
// chartName/
//
//	├── .helmignore   	# Contains patterns to ignore when packaging Helm charts.
//	├── Chart.yaml    	# Information about your chart
//	├── values.yaml   	# The default values for your templates
//	└── templates/    	# The template files
//	    └── _helpers.tp   # Helm default template partials
//
// Overwrites existing values.yaml and templates in templates dir on every run.
func (o output) Create(chartDir, chartName string, crd bool, certManagerAsSubchart bool, certManagerVersion string, certManagerInstallCRD bool, templates []helmify.Template, filenames []string) error {
	err := initChartDir(chartDir, chartName, crd, certManagerAsSubchart, certManagerVersion)
	if err != nil {
		return err
	}
	// group templates into files
	files := map[string][]helmify.Template{}
	values := helmify.Values{}
	values[cluster.DomainKey] = cluster.DefaultDomain
	for i, template := range templates {
		file := files[filenames[i]]
		file = append(file, template)
		files[filenames[i]] = file
		err = values.Merge(template.Values())
		if err != nil {
			return err
		}
	}
	cDir := filepath.Join(chartDir, chartName)
	for filename, tpls := range files {
		err = overwriteTemplateFile(filename, cDir, crd, tpls)
		if err != nil {
			return err
		}
	}
	err = overwriteValuesFile(cDir, values, certManagerAsSubchart, certManagerInstallCRD)
	if err != nil {
		return err
	}
	return nil
}

func overwriteTemplateFile(filename, chartDir string, crd bool, templates []helmify.Template) error {
	// pull in crd-dir setting and siphon crds into folder
	var subdir string
	if strings.Contains(filename, "crd") && crd {
		subdir = "crds"
		// create "crds" if not exists
		if _, err := os.Stat(filepath.Join(chartDir, "crds")); os.IsNotExist(err) {
			err = os.MkdirAll(filepath.Join(chartDir, "crds"), 0750)
			if err != nil {
				return fmt.Errorf("%w: unable create crds dir", err)
			}
		}
	} else {
		subdir = "templates"
	}
	file := filepath.Join(chartDir, subdir, filename)
	f, err := os.OpenFile(file, os.O_APPEND|os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return fmt.Errorf("%w: unable to open %s", err, file)
	}
	defer f.Close()
	for i, t := range templates {
		logrus.WithField("file", file).Debug("writing a template into")
		err = t.Write(f)
		if err != nil {
			return fmt.Errorf("%w: unable to write into %s", err, file)
		}
		if i != len(templates)-1 {
			_, err = f.Write([]byte("\n---\n"))
			if err != nil {
				return fmt.Errorf("%w: unable to write into %s", err, file)
			}
		}
	}
	if len(templates) != 0 {
		_, err = f.Write([]byte("\n"))
		if err != nil {
			return fmt.Errorf("%w: unable to write newline into %s", err, file)
		}
	}
	logrus.WithField("file", file).Info("overwritten")
	return nil
}

func overwriteValuesFile(chartDir string, values helmify.Values, certManagerAsSubchart bool, certManagerInstallCRD bool) error {
	if certManagerAsSubchart {
		_, err := values.Add(certManagerInstallCRD, "certmanager", "installCRDs")
		if err != nil {
			return fmt.Errorf("%w: unable to add cert-manager.installCRDs", err)
		}

		_, err = values.Add(true, "certmanager", "enabled")
		if err != nil {
			return fmt.Errorf("%w: unable to add cert-manager.enabled", err)
		}
	}
	res, err := yaml.Marshal(values)
	if err != nil {
		return fmt.Errorf("%w: unable to write marshal values.yaml", err)
	}

	file := filepath.Join(chartDir, "values.yaml")
	err = os.WriteFile(file, res, 0600)
	if err != nil {
		return fmt.Errorf("%w: unable to write values.yaml", err)
	}
	logrus.WithField("file", file).Info("overwritten")
	return nil
}
0707010000005A000081A400000000000000000000000167C8625900000060000000000000000000000000000000000000001F00000000helmify-0.4.18/pkg/helm/doc.go// Package helm contains code for writing templates to a filesystem as Helm chart.
package helm
0707010000005B000081A400000000000000000000000167C862590000178B000000000000000000000000000000000000002000000000helmify-0.4.18/pkg/helm/init.gopackage helm

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/sirupsen/logrus"
)

const helmIgnore = `# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
`

const defaultHelpers = `{{/*
Expand the name of the chart.
*/}}
{{- define "<CHARTNAME>.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "<CHARTNAME>.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "<CHARTNAME>.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "<CHARTNAME>.labels" -}}
helm.sh/chart: {{ include "<CHARTNAME>.chart" . }}
{{ include "<CHARTNAME>.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "<CHARTNAME>.selectorLabels" -}}
app.kubernetes.io/name: {{ include "<CHARTNAME>.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "<CHARTNAME>.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "<CHARTNAME>.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
`

const defaultChartfile = `apiVersion: v2
name: %s
description: A Helm chart for Kubernetes
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "0.1.0"
`

const certManagerDependencies = `
dependencies:
  - name: cert-manager
    repository: https://charts.jetstack.io
    condition: certmanager.enabled
    alias: certmanager
    version: %q
`

var chartName = regexp.MustCompile("^[a-zA-Z0-9._-]+$")

const maxChartNameLength = 250

// initChartDir - creates Helm chart structure in chartName directory if not presented.
func initChartDir(chartDir, chartName string, crd bool, certManagerAsSubchart bool, certManagerVersion string) error {
	if err := validateChartName(chartName); err != nil {
		return err
	}

	cDir := filepath.Join(chartDir, chartName)
	_, err := os.Stat(filepath.Join(cDir, "Chart.yaml"))
	if os.IsNotExist(err) {
		return createCommonFiles(chartDir, chartName, crd, certManagerAsSubchart, certManagerVersion)
	}
	logrus.Info("Skip creating Chart skeleton: Chart.yaml already exists.")
	return err
}

func validateChartName(name string) error {
	if name == "" || len(name) > maxChartNameLength {
		return fmt.Errorf("chart name must be between 1 and %d characters", maxChartNameLength)
	}
	if !chartName.MatchString(name) {
		return fmt.Errorf("chart name must match the regular expression %q", chartName.String())
	}
	return nil
}

func createCommonFiles(chartDir, chartName string, crd bool, certManagerAsSubchart bool, certManagerVersion string) error {
	cDir := filepath.Join(chartDir, chartName)
	err := os.MkdirAll(filepath.Join(cDir, "templates"), 0750)
	if err != nil {
		return fmt.Errorf("%w: unable create chart/templates dir", err)
	}
	if crd {
		err = os.MkdirAll(filepath.Join(cDir, "crds"), 0750)
		if err != nil {
			return fmt.Errorf("%w: unable create crds dir", err)
		}
	}
	createFile := func(content []byte, path ...string) {
		if err != nil {
			return
		}
		file := filepath.Join(path...)
		err = os.WriteFile(file, content, 0640)
		if err == nil {
			logrus.WithField("file", file).Info("created")
		}
	}
	createFile(chartYAML(chartName, certManagerAsSubchart, certManagerVersion), cDir, "Chart.yaml")
	createFile([]byte(helmIgnore), cDir, ".helmignore")
	createFile(helpersYAML(chartName), cDir, "templates", "_helpers.tpl")
	return err
}

func chartYAML(appName string, certManagerAsSubchart bool, certManagerVersion string) []byte {
	chartFile := defaultChartfile
	if certManagerAsSubchart {
		chartFile += fmt.Sprintf(certManagerDependencies, certManagerVersion)
	}
	return []byte(fmt.Sprintf(chartFile, appName))
}

func helpersYAML(chartName string) []byte {
	return []byte(strings.ReplaceAll(defaultHelpers, "<CHARTNAME>", chartName))
}
0707010000005C000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001B00000000helmify-0.4.18/pkg/helmify0707010000005D000081A400000000000000000000000167C862590000074C000000000000000000000000000000000000002400000000helmify-0.4.18/pkg/helmify/model.gopackage helmify

import (
	"io"

	"github.com/arttor/helmify/pkg/config"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// Processor - converts k8s object to helm template.
// Implement this interface and register it to a context to support a new k8s resource conversion.
type Processor interface {
	// Process - converts k8s object to Helm template.
	// return false if not able to process given object type.
	Process(appMeta AppMetadata, unstructured *unstructured.Unstructured) (bool, Template, error)
}

// Template - represents Helm template in 'templates' directory.
type Template interface {
	// Filename - returns template filename
	Filename() string
	// Values - returns set of values used in template
	Values() Values
	// Write - writes helm template into given writer
	Write(writer io.Writer) error
}

// Output - converts Template into helm chart on disk.
type Output interface {
	Create(chartName, chartDir string, Crd bool, certManagerAsSubchart bool, certManagerVersion string, certManagerInstallCRD bool, templates []Template, filenames []string) error
}

// AppMetadata handle common information about K8s objects in the chart.
type AppMetadata interface {
	// Namespace returns app namespace.
	Namespace() string
	// ChartName returns chart name
	ChartName() string
	// TemplatedName converts object name to templated Helm name.
	// Example: 	"my-app-service1"	-> "{{ include "chart.fullname" . }}-service1"
	//				"my-app-secret"		-> "{{ include "chart.fullname" . }}-secret"
	//				etc...
	TemplatedName(objName string) string
	// TemplatedString converts a string to templated string with chart name.
	TemplatedString(str string) string
	// TrimName trims common prefix from object name if exists.
	// We trim common prefix because helm already using release for this purpose.
	TrimName(objName string) string

	Config() config.Config
}
0707010000005E000081A400000000000000000000000167C8625900000BE8000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/helmify/values.gopackage helmify

import (
	"dario.cat/mergo"
	"fmt"
	"strconv"
	"strings"

	"github.com/iancoleman/strcase"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// Values - represents helm template values.yaml.
type Values map[string]interface{}

// Merge given values with current instance.
func (v *Values) Merge(values Values) error {
	if err := mergo.Merge(v, values, mergo.WithAppendSlice); err != nil {
		return fmt.Errorf("%w: unable to merge helm values", err)
	}
	return nil
}

// Add - adds given value to values and returns its helm template representation {{ .Values.<valueName> }}
func (v *Values) Add(value interface{}, name ...string) (string, error) {
	name = toCamelCase(name)
	switch val := value.(type) {
	case int:
		value = int64(val)
	case int8:
		value = int64(val)
	case int16:
		value = int64(val)
	case int32:
		value = int64(val)
	}

	err := unstructured.SetNestedField(*v, value, name...)
	if err != nil {
		return "", fmt.Errorf("%w: unable to set value: %v", err, name)
	}
	_, isString := value.(string)
	if isString {
		return "{{ .Values." + strings.Join(name, ".") + " | quote }}", nil
	}
	_, isSlice := value.([]interface{})
	if isSlice {
		spaces := strconv.Itoa(len(name) * 2)
		return "{{ toYaml .Values." + strings.Join(name, ".") + " | nindent " + spaces + " }}", nil
	}
	return "{{ .Values." + strings.Join(name, ".") + " }}", nil
}

// AddYaml - adds given value to values and returns its helm template representation as Yaml {{ .Values.<valueName> | toYaml | indent i }}
// indent  <= 0 will be omitted.
func (v *Values) AddYaml(value interface{}, indent int, newLine bool, name ...string) (string, error) {
	name = toCamelCase(name)
	err := unstructured.SetNestedField(*v, value, name...)
	if err != nil {
		return "", fmt.Errorf("%w: unable to set value: %v", err, name)
	}
	if indent > 0 {
		if newLine {
			return "{{ .Values." + strings.Join(name, ".") + fmt.Sprintf(" | toYaml | nindent %d }}", indent), nil
		}
		return "{{ .Values." + strings.Join(name, ".") + fmt.Sprintf(" | toYaml | indent %d }}", indent), nil
	}
	return "{{ .Values." + strings.Join(name, ".") + " | toYaml }}", nil
}

// AddSecret - adds empty value to values and returns its helm template representation {{ required "<valueName>" .Values.<valueName> }}.
// Set toBase64=true for Secret data to be base64 encoded and set false for Secret stringData.
func (v *Values) AddSecret(toBase64 bool, name ...string) (string, error) {
	name = toCamelCase(name)
	nameStr := strings.Join(name, ".")
	err := unstructured.SetNestedField(*v, "", name...)
	if err != nil {
		return "", fmt.Errorf("%w: unable to set value: %v", err, nameStr)
	}
	res := fmt.Sprintf(`{{ required "%[1]s is required" .Values.%[1]s`, nameStr)
	if toBase64 {
		res += " | b64enc"
	}
	return res + " | quote }}", err
}

func toCamelCase(name []string) []string {
	for i, n := range name {
		camelCase := strcase.ToLowerCamel(n)
		if n == strings.ToUpper(n) {
			camelCase = strcase.ToLowerCamel(strings.ToLower(n))
		}
		name[i] = camelCase
	}
	return name
}
0707010000005F000081A400000000000000000000000167C8625900000952000000000000000000000000000000000000002A00000000helmify-0.4.18/pkg/helmify/values_test.gopackage helmify

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestValues_Add(t *testing.T) {
	t.Run("quote func added for string values", func(t *testing.T) {
		testVal := Values{}
		res, err := testVal.Add("abc", "a", "b")
		assert.NoError(t, err)
		assert.Contains(t, res, "quote")
	})
	t.Run("quote func not added for not string values", func(t *testing.T) {
		testVal := Values{}
		res, err := testVal.Add(int64(1), "a", "b")
		assert.NoError(t, err)
		assert.NotContains(t, res, "quote")
		res, err = testVal.Add(true, "a", "b")
		assert.NoError(t, err)
		assert.NotContains(t, res, "quote")
		res, err = testVal.Add(420.69, "a", "b")
		assert.NoError(t, err)
		assert.NotContains(t, res, "quote")
	})
	t.Run("name path is dot formatted", func(t *testing.T) {
		testVal := Values{}
		res, err := testVal.Add(int64(1), "a", "b")
		assert.NoError(t, err)
		assert.Contains(t, res, " .Values.a.b ")
	})
	t.Run("snake names camel cased", func(t *testing.T) {
		testVal := Values{}
		snake := "my_name"
		camel := "myName"
		res, err := testVal.Add(420.69, snake)
		assert.NoError(t, err)
		assert.NotContains(t, res, snake)
		assert.Contains(t, res, camel)
	})
	t.Run("upper snake names camel cased", func(t *testing.T) {
		testVal := Values{}
		upSnake := "MY_NAME"
		camel := "myName"
		res, err := testVal.Add(420.69, upSnake)
		assert.NoError(t, err)
		assert.NotContains(t, res, upSnake)
		assert.Contains(t, res, camel)
	})
	t.Run("kebab names camel cased", func(t *testing.T) {
		testVal := Values{}
		kebab := "my-name"
		camel := "myName"
		res, err := testVal.Add(420.69, kebab)
		assert.NoError(t, err)
		assert.NotContains(t, res, kebab)
		assert.Contains(t, res, camel)
	})
	t.Run("dot names camel cased", func(t *testing.T) {
		testVal := Values{}
		dot := "my.name"
		camel := "myName"
		res, err := testVal.Add(420.69, dot)
		assert.NoError(t, err)
		assert.NotContains(t, res, dot)
		assert.Contains(t, res, camel)
	})
}
func TestValues_AddSecret(t *testing.T) {
	t.Run("add base64 enc secret", func(t *testing.T) {
		testVal := Values{}
		res, err := testVal.AddSecret(true, "a", "b")
		assert.NoError(t, err)
		assert.Contains(t, res, "b64enc")
	})
	t.Run("add not encoded secret", func(t *testing.T) {
		testVal := Values{}
		res, err := testVal.AddSecret(false, "a", "b")
		assert.NoError(t, err)
		assert.NotContains(t, res, "b64enc")
	})
}
07070100000060000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001C00000000helmify-0.4.18/pkg/metadata07070100000061000081A400000000000000000000000167C8625900000CF6000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/metadata/metadata.gopackage metadata

import (
	"fmt"
	"github.com/arttor/helmify/pkg/config"
	"strings"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

const nameTeml = `{{ include "%s.fullname" . }}-%s`

var nsGVK = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "Namespace",
}

var crdGVK = schema.GroupVersionKind{
	Group:   "apiextensions.k8s.io",
	Version: "v1",
	Kind:    "CustomResourceDefinition",
}

func New(conf config.Config) *Service {
	return &Service{names: make(map[string]struct{}), conf: conf}
}

type Service struct {
	commonPrefix string
	namespace    string
	names        map[string]struct{}
	conf         config.Config
}

func (a *Service) Config() config.Config {
	return a.conf
}

// TrimName - tries to trim app common prefix for object name if detected.
// If no common prefix - returns name as it is.
// It is better to trim common prefix because Helm also adds release name as common prefix.
func (a *Service) TrimName(objName string) string {
	trimmed := strings.TrimPrefix(objName, a.commonPrefix)
	trimmed = strings.TrimLeft(trimmed, "-./_ ")
	if trimmed == "" {
		return objName
	}
	return trimmed
}

var _ helmify.AppMetadata = &Service{}

// Load processed objects one-by-one before actual processing to define app namespace, name common prefix and
// other app meta information.
func (a *Service) Load(obj *unstructured.Unstructured) {
	a.names[obj.GetName()] = struct{}{}
	a.commonPrefix = detectCommonPrefix(obj, a.commonPrefix)
	objNs := extractAppNamespace(obj)
	if objNs == "" {
		return
	}
	if a.namespace != "" && a.namespace != objNs {
		logrus.Warnf("Two different namespaces for app detected: %s and %s. Resulted char will have single namespace.", objNs, a.namespace)
	}
	a.namespace = objNs
}

// Namespace returns detected app namespace.
func (a *Service) Namespace() string {
	return a.namespace
}

// ChartName returns ChartName.
func (a *Service) ChartName() string {
	return a.conf.ChartName
}

// TemplatedName - converts object name to its Helm templated representation.
// Adds chart fullname prefix from _helpers.tpl
func (a *Service) TemplatedName(name string) string {
	if a.conf.OriginalName {
		return name
	}
	_, contains := a.names[name]
	if !contains {
		// template only app objects
		return name
	}
	name = a.TrimName(name)
	return fmt.Sprintf(nameTeml, a.conf.ChartName, name)
}

func (a *Service) TemplatedString(str string) string {
	name := a.TrimName(str)
	return fmt.Sprintf(nameTeml, a.conf.ChartName, name)
}

func extractAppNamespace(obj *unstructured.Unstructured) string {
	if obj.GroupVersionKind() == nsGVK {
		return obj.GetName()
	}
	return obj.GetNamespace()
}

func detectCommonPrefix(obj *unstructured.Unstructured, prevName string) string {
	if obj.GroupVersionKind() == crdGVK || obj.GroupVersionKind() == nsGVK {
		return prevName
	}
	if prevName == "" {
		return obj.GetName()
	}
	return commonPrefix(obj.GetName(), prevName)
}

func commonPrefix(one, two string) string {
	runes1 := []rune(one)
	runes2 := []rune(two)
	min := len(runes1)
	if min > len(runes2) {
		min = len(runes2)
	}
	for i := 0; i < min; i++ {
		if runes1[i] != runes2[i] {
			return string(runes1[:i])
		}
	}
	return string(runes1[:min])
}
07070100000062000081A400000000000000000000000167C8625900000CD8000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/metadata/metadata_test.gopackage metadata

import (
	"fmt"
	"github.com/arttor/helmify/pkg/config"
	"testing"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const res = `apiVersion: v1
kind: Secret
metadata:
  name: %s
  namespace: %s`

func Test_commonPrefix(t *testing.T) {
	type args struct {
		left, right string
	}
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "left is a prefix of right",
			args: args{left: "test", right: "testimony"},
			want: "test",
		},
		{
			name: "common prefix",
			args: args{left: "testimony", right: "testicle"},
			want: "testi",
		},
		{
			name: "no common",
			args: args{left: "testimony", right: "abc"},
			want: "",
		},
		{
			name: "right is empty",
			args: args{left: "testimony", right: ""},
			want: "",
		},
		{
			name: "left is empty",
			args: args{left: "", right: "abc"},
			want: "",
		},
		{
			name: "both are empty",
			args: args{left: "", right: ""},
			want: "",
		},
		{
			name: "unicode",
			args: args{left: "багет", right: "багаж"},
			want: "баг",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := commonPrefix(tt.args.left, tt.args.right); got != tt.want {
				t.Errorf("commonPrefix() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_Service(t *testing.T) {
	t.Run("load ns from object", func(t *testing.T) {
		obj := createRes("name", "ns")
		testSvc := New(config.Config{})
		testSvc.Load(obj)
		assert.Equal(t, "ns", testSvc.Namespace())
		testSvc.Load(internal.TestNs)
		assert.Equal(t, internal.TestNsName, testSvc.Namespace())
	})
	t.Run("get chart name", func(t *testing.T) {
		testSvc := New(config.Config{ChartName: "name"})
		assert.Equal(t, "name", testSvc.ChartName())
	})
	t.Run("trim common prefix abc", func(t *testing.T) {
		testSvc := New(config.Config{})
		testSvc.Load(createRes("abc-name1", "ns"))
		testSvc.Load(createRes("abc-name2", "ns"))
		testSvc.Load(createRes("abc-service", "ns"))

		assert.Equal(t, "name1", testSvc.TrimName("abc-name1"))
		assert.Equal(t, "name2", testSvc.TrimName("abc-name2"))
		assert.Equal(t, "service", testSvc.TrimName("abc-service"))
	})
	t.Run("trim common prefix: no common", func(t *testing.T) {
		testSvc := New(config.Config{})
		testSvc.Load(createRes("name1", "ns"))
		testSvc.Load(createRes("abc", "ns"))
		testSvc.Load(createRes("service", "ns"))

		assert.Equal(t, "name1", testSvc.TrimName("name1"))
		assert.Equal(t, "abc", testSvc.TrimName("abc"))
		assert.Equal(t, "service", testSvc.TrimName("service"))
	})
	t.Run("template name", func(t *testing.T) {
		testSvc := New(config.Config{ChartName: "chart-name"})
		testSvc.Load(createRes("abc", "ns"))
		templated := testSvc.TemplatedName("abc")
		assert.Equal(t, `{{ include "chart-name.fullname" . }}-abc`, templated)
	})
	t.Run("template name: not process unknown name", func(t *testing.T) {
		testSvc := New(config.Config{ChartName: "chart-name"})
		testSvc.Load(createRes("abc", "ns"))
		assert.Equal(t, "qwe", testSvc.TemplatedName("qwe"))
		assert.NotEqual(t, "abc", testSvc.TemplatedName("abc"))
	})
}

func createRes(name, ns string) *unstructured.Unstructured {
	objYaml := fmt.Sprintf(res, name, ns)
	return internal.GenerateObj(objYaml)
}
07070100000063000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001D00000000helmify-0.4.18/pkg/processor07070100000064000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002700000000helmify-0.4.18/pkg/processor/configmap07070100000065000081A400000000000000000000000167C8625900001233000000000000000000000000000000000000003400000000helmify-0.4.18/pkg/processor/configmap/configmap.gopackage configmap

import (
	"fmt"
	"github.com/arttor/helmify/pkg/format"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var configMapTempl, _ = template.New("configMap").Parse(
	`{{ .Meta }}
{{- if .Immutable }}
{{ .Immutable }}
{{- end }}
{{- if .BinaryData }}
{{ .BinaryData }}
{{- end }}
{{- if .Data }}
{{ .Data }}
{{- end }}`)

var configMapGVC = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "ConfigMap",
}

// New creates processor for k8s ConfigMap resource.
func New() helmify.Processor {
	return &configMap{}
}

type configMap struct{}

// Process k8s ConfigMap object into template. Returns false if not capable of processing given resource type.
func (d configMap) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != configMapGVC {
		return false, nil, nil
	}
	var meta, immutable, binaryData, data string
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	if field, exists, _ := unstructured.NestedBool(obj.Object, "immutable"); exists {
		immutable, err = yamlformat.Marshal(map[string]interface{}{"immutable": field}, 0)
		if err != nil {
			return true, nil, err
		}
	}
	if field, exists, _ := unstructured.NestedStringMap(obj.Object, "binaryData"); exists {
		binaryData, err = yamlformat.Marshal(map[string]interface{}{"binaryData": field}, 0)
		if err != nil {
			return true, nil, err
		}
	}

	name := appMeta.TrimName(obj.GetName())
	var values helmify.Values
	if field, exists, _ := unstructured.NestedStringMap(obj.Object, "data"); exists {
		field, values = parseMapData(field, name)
		data, err = yamlformat.Marshal(map[string]interface{}{"data": field}, 0)
		if err != nil {
			return true, nil, err
		}
		data = strings.ReplaceAll(data, "'", "")
	}

	return true, &result{
		name: name + ".yaml",
		data: struct {
			Meta       string
			Immutable  string
			BinaryData string
			Data       string
		}{Meta: meta, Immutable: immutable, BinaryData: binaryData, Data: data},
		values: values,
	}, nil
}

func parseMapData(data map[string]string, configName string) (map[string]string, helmify.Values) {
	values := helmify.Values{}
	for key, value := range data {
		valuesNamePath := []string{configName, key}
		if strings.HasSuffix(key, ".properties") {
			// handle properties
			templated, err := parseProperties(value, valuesNamePath, values)
			if err != nil {
				logrus.WithError(err).Errorf("unable to process configmap data: %v", valuesNamePath)
				continue
			}
			data[key] = templated
			continue
		}
		if strings.Contains(value, "\n") {
			value = format.RemoveTrailingWhitespaces(value)
			templatedVal, err := values.AddYaml(value, 1, false, valuesNamePath...)
			if err != nil {
				logrus.WithError(err).Errorf("unable to process multiline configmap data: %v", valuesNamePath)
				continue
			}
			data[key] = templatedVal
			continue
		}
		// handle plain string
		templatedVal, err := values.Add(value, valuesNamePath...)
		if err != nil {
			logrus.WithError(err).Errorf("unable to process configmap data: %v", valuesNamePath)
			continue
		}
		data[key] = templatedVal
	}
	return data, values
}

// func parseProperties(properties string, path []string, values helmify.Values) (string, error) {
func parseProperties(properties interface{}, path []string, values helmify.Values) (string, error) {
	var res strings.Builder
	for _, line := range strings.Split(strings.TrimSuffix(properties.(string), "\n"), "\n") {
		prop := strings.Split(line, "=")
		if len(prop) != 2 {
			return "", fmt.Errorf("wrong property format in %v: %s", path, line)
		}
		propName, propVal := prop[0], prop[1]
		propNamePath := strings.Split(propName, ".")
		templatedVal, err := values.Add(propVal, append(path, propNamePath...)...)
		if err != nil {
			return "", err
		}
		_, err = res.WriteString(propName + "=" + templatedVal + "\n")
		if err != nil {
			return "", fmt.Errorf("%w: unable to write to string builder", err)
		}
	}
	return res.String(), nil
}

type result struct {
	name string
	data struct {
		Meta       string
		Immutable  string
		BinaryData string
		Data       string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return configMapTempl.Execute(writer, r.data)
}
07070100000066000081A400000000000000000000000167C86259000003F5000000000000000000000000000000000000003900000000helmify-0.4.18/pkg/processor/configmap/configmap_test.gopackage configmap

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const (
	strConfigmap = `apiVersion: v1
kind: ConfigMap
metadata:
  name: my-operator-manager-config
  namespace: my-operator-system
data:
  dummyconfigmapkey: dummyconfigmapvalue
  controller_manager_config.yaml: |
    apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
    kind: ControllerManagerConfig
    health:
      healthProbeBindAddress: :8081`
)

func Test_configMap_Process(t *testing.T) {
	var testInstance configMap

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strConfigmap)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000067000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002100000000helmify-0.4.18/pkg/processor/crd07070100000068000081A400000000000000000000000167C8625900001097000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/processor/crd/crd.gopackage crd

import (
	"bytes"
	"fmt"
	"github.com/sirupsen/logrus"
	"io"
	"strings"

	v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
)

const crdTeml = `apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: %[1]s
%[3]s
  labels:
%[4]s
  {{- include "%[2]s.labels" . | nindent 4 }}
spec:
%[5]s
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []`

var crdGVC = schema.GroupVersionKind{
	Group:   "apiextensions.k8s.io",
	Version: "v1",
	Kind:    "CustomResourceDefinition",
}

// New creates processor for k8s CustomResourceDefinition resource.
func New() helmify.Processor {
	return &crd{}
}

type crd struct{}

// Process k8s CustomResourceDefinition object into template. Returns false if not capable of processing given resource type.
func (c crd) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != crdGVC {
		return false, nil, nil
	}
	name, ok, err := unstructured.NestedString(obj.Object, "spec", "names", "singular")
	if err != nil || !ok {
		return true, nil, fmt.Errorf("%w: unable to create crd template", err)
	}
	if appMeta.Config().Crd {
		logrus.WithField("crd", name).Info("put CRD under crds dir without templating")
		// do not template CRDs when placed to crds dir
		res, err := yaml.Marshal(obj)
		if err != nil {
			return true, nil, fmt.Errorf("%w: unable to create crd template", err)
		}
		return true, &result{
			name: name + "-crd.yaml",
			data: res,
		}, nil
	}

	var labels, annotations string
	if len(obj.GetAnnotations()) != 0 {
		a := obj.GetAnnotations()
		certName := a["cert-manager.io/inject-ca-from"]
		if certName != "" {
			certName = strings.TrimPrefix(certName, appMeta.Namespace()+"/")
			certName = appMeta.TrimName(certName)
			a["cert-manager.io/inject-ca-from"] = fmt.Sprintf(`{{ .Release.Namespace }}/{{ include "%[1]s.fullname" . }}-%[2]s`, appMeta.ChartName(), certName)
		}
		annotations, err = yamlformat.Marshal(map[string]interface{}{"annotations": a}, 2)
		if err != nil {
			return true, nil, err
		}
	}
	if len(obj.GetLabels()) != 0 {
		l := obj.GetLabels()
		// provided by Helm
		delete(l, "app.kubernetes.io/name")
		delete(l, "app.kubernetes.io/instance")
		delete(l, "app.kubernetes.io/version")
		delete(l, "app.kubernetes.io/managed-by")
		delete(l, "helm.sh/chart")
		if len(l) != 0 {
			labels, err = yamlformat.Marshal(l, 4)
			if err != nil {
				return true, nil, err
			}
			labels = strings.Trim(labels, "\n")
		}
	}

	specUnstr, ok, err := unstructured.NestedMap(obj.Object, "spec")
	if err != nil || !ok {
		return true, nil, fmt.Errorf("%w: unable to create crd template", err)
	}

	spec := v1.CustomResourceDefinitionSpec{}
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(specUnstr, &spec)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to crd spec", err)
	}

	if spec.Conversion != nil {
		conv := spec.Conversion
		if conv.Strategy == v1.WebhookConverter {
			wh := conv.Webhook
			if wh != nil && wh.ClientConfig != nil && wh.ClientConfig.Service != nil {
				wh.ClientConfig.Service.Name = appMeta.TemplatedName(wh.ClientConfig.Service.Name)
				wh.ClientConfig.Service.Namespace = strings.ReplaceAll(wh.ClientConfig.Service.Namespace, appMeta.Namespace(), `{{ .Release.Namespace }}`)
			}
		}
	}

	specYaml, _ := yaml.Marshal(spec)
	specYaml = yamlformat.Indent(specYaml, 2)
	specYaml = bytes.TrimRight(specYaml, "\n ")

	res := fmt.Sprintf(crdTeml, obj.GetName(), appMeta.ChartName(), annotations, labels, string(specYaml))
	res = strings.ReplaceAll(res, "\n\n", "\n")

	return true, &result{
		name: name + "-crd.yaml",
		data: []byte(res),
	}, nil
}

type result struct {
	name string
	data []byte
}

func (r *result) Filename() string {
	return r.name
}

func (r *result) Values() helmify.Values {
	return helmify.Values{}
}

func (r *result) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
07070100000069000081A400000000000000000000000167C8625900000436000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/processor/crd/crd_test.gopackage crd

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const (
	strCRD = `apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  creationTimestamp: null
  name: cephvolumes.test.example.com
  labels:
    example: true
spec:
  group: test.example.com
  names:
    kind: CephVolume
    listKind: CephVolumeList
    plural: cephvolumes
    singular: cephvolume
  scope: Namespaced
`
)

func Test_crd_Process(t *testing.T) {
	var testInstance crd

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strCRD)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
0707010000006A000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002700000000helmify-0.4.18/pkg/processor/daemonset0707010000006B000081A400000000000000000000000167C8625900000F42000000000000000000000000000000000000003400000000helmify-0.4.18/pkg/processor/daemonset/daemonset.gopackage daemonset

import (
	"fmt"
	"github.com/arttor/helmify/pkg/processor/pod"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var daemonsetGVC = schema.GroupVersionKind{
	Group:   "apps",
	Version: "v1",
	Kind:    "DaemonSet",
}

var daemonsetTempl, _ = template.New("daemonset").Parse(
	`{{- .Meta }}
spec:
  selector:
{{ .Selector }}
  template:
    metadata:
      labels:
{{ .PodLabels }}
{{- .PodAnnotations }}
    spec:
{{ .Spec }}`)

const selectorTempl = `%[1]s
{{- include "%[2]s.selectorLabels" . | nindent 6 }}
%[3]s`

// New creates processor for k8s Daemonset resource.
func New() helmify.Processor {
	return &daemonset{}
}

type daemonset struct{}

// Process k8s Daemonset object into template. Returns false if not capable of processing given resource type.
func (d daemonset) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != daemonsetGVC {
		return false, nil, nil
	}
	dae := appsv1.DaemonSet{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &dae)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to daemonset", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	values := helmify.Values{}

	name := appMeta.TrimName(obj.GetName())

	matchLabels, err := yamlformat.Marshal(map[string]interface{}{"matchLabels": dae.Spec.Selector.MatchLabels}, 0)
	if err != nil {
		return true, nil, err
	}
	matchExpr := ""
	if dae.Spec.Selector.MatchExpressions != nil {
		matchExpr, err = yamlformat.Marshal(map[string]interface{}{"matchExpressions": dae.Spec.Selector.MatchExpressions}, 0)
		if err != nil {
			return true, nil, err
		}
	}
	selector := fmt.Sprintf(selectorTempl, matchLabels, appMeta.ChartName(), matchExpr)
	selector = strings.Trim(selector, " \n")
	selector = string(yamlformat.Indent([]byte(selector), 4))

	podLabels, err := yamlformat.Marshal(dae.Spec.Template.ObjectMeta.Labels, 8)
	if err != nil {
		return true, nil, err
	}
	podLabels += fmt.Sprintf("\n      {{- include \"%s.selectorLabels\" . | nindent 8 }}", appMeta.ChartName())

	podAnnotations := ""
	if len(dae.Spec.Template.ObjectMeta.Annotations) != 0 {
		podAnnotations, err = yamlformat.Marshal(map[string]interface{}{"annotations": dae.Spec.Template.ObjectMeta.Annotations}, 6)
		if err != nil {
			return true, nil, err
		}

		podAnnotations = "\n" + podAnnotations
	}

	nameCamel := strcase.ToLowerCamel(name)
	specMap, podValues, err := pod.ProcessSpec(nameCamel, appMeta, dae.Spec.Template.Spec)
	if err != nil {
		return true, nil, err
	}
	err = values.Merge(podValues)
	if err != nil {
		return true, nil, err
	}

	spec, err := yamlformat.Marshal(specMap, 6)
	if err != nil {
		return true, nil, err
	}
	spec = strings.ReplaceAll(spec, "'", "")

	return true, &result{
		values: values,
		data: struct {
			Meta           string
			Selector       string
			PodLabels      string
			PodAnnotations string
			Spec           string
		}{
			Meta:           meta,
			Selector:       selector,
			PodLabels:      podLabels,
			PodAnnotations: podAnnotations,
			Spec:           spec,
		},
	}, nil
}

type result struct {
	data struct {
		Meta           string
		Selector       string
		PodLabels      string
		PodAnnotations string
		Spec           string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return "daemonset.yaml"
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return daemonsetTempl.Execute(writer, r.data)
}
0707010000006C000081A400000000000000000000000167C8625900000741000000000000000000000000000000000000003900000000helmify-0.4.18/pkg/processor/daemonset/daemonset_test.gopackage daemonset

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const (
	strDepl = `apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
`
)

func Test_daemonset_Process(t *testing.T) {
	var testInstance daemonset

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strDepl)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
0707010000006D000081A400000000000000000000000167C86259000006DC000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/processor/default.gopackage processor

import (
	"io"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var nsGVK = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "Namespace",
}

// Default default processor for unknown resources.
func Default() helmify.Processor {
	return &dft{}
}

type dft struct{}

// Process unknown resource to a helm template. Default processor just templates obj name and adds helm annotations.
func (d dft) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() == nsGVK {
		// Skip namespaces from processing because namespace will be handled by Helm.
		return true, nil, nil
	}
	logrus.WithFields(logrus.Fields{
		"ApiVersion": obj.GetAPIVersion(),
		"Kind":       obj.GetKind(),
		"Name":       obj.GetName(),
	}).Warn("Unsupported resource: using default processor.")
	name := appMeta.TrimName(obj.GetName())

	meta, err := ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}
	delete(obj.Object, "apiVersion")
	delete(obj.Object, "kind")
	delete(obj.Object, "metadata")

	body, err := yamlformat.Marshal(obj.Object, 0)
	if err != nil {
		return true, nil, err
	}
	return true, &defaultResult{
		data: []byte(meta + "\n" + body),
		name: name,
	}, nil
}

type defaultResult struct {
	data []byte
	name string
}

func (r *defaultResult) Filename() string {
	return r.name + ".yaml"
}

func (r *defaultResult) Values() helmify.Values {
	return helmify.Values{}
}

func (r *defaultResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
0707010000006E000081A400000000000000000000000167C8625900000473000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/processor/default_test.gopackage processor

import (
	"github.com/arttor/helmify/pkg/config"
	"testing"

	"github.com/arttor/helmify/internal"
	"github.com/arttor/helmify/pkg/metadata"
	"github.com/stretchr/testify/assert"
)

const pvcYaml = `apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-operator-pvc-lim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: cust1-mypool-lim`

func Test_dft_Process(t *testing.T) {

	t.Run("skip namespace", func(t *testing.T) {
		testMeta := metadata.New(config.Config{ChartName: "chart-name"})
		testMeta.Load(internal.TestNs)
		testProcessor := Default()
		processed, templ, err := testProcessor.Process(testMeta, internal.TestNs)
		assert.NoError(t, err)
		assert.True(t, processed)
		assert.Nil(t, templ)
	})
	t.Run("process", func(t *testing.T) {
		obj := internal.GenerateObj(pvcYaml)
		testMeta := metadata.New(config.Config{ChartName: "chart-name"})
		testMeta.Load(obj)
		testProcessor := Default()
		processed, templ, err := testProcessor.Process(testMeta, obj)
		assert.NoError(t, err)
		assert.True(t, processed)
		assert.NotNil(t, templ)
	})
}
0707010000006F000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/processor/deployment07070100000070000081A400000000000000000000000167C8625900002377000000000000000000000000000000000000003600000000helmify-0.4.18/pkg/processor/deployment/deployment.gopackage deployment

import (
	"fmt"
	"io"
	"regexp"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor/pod"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/intstr"
)

var deploymentGVC = schema.GroupVersionKind{
	Group:   "apps",
	Version: "v1",
	Kind:    "Deployment",
}

var deploymentTempl, _ = template.New("deployment").Parse(
	`{{- .Meta }}
spec:
{{- if .Replicas }}
{{ .Replicas }}
{{- end }}
{{- if .RevisionHistoryLimit }}
{{ .RevisionHistoryLimit }}
{{- end }}
{{- if .Strategy }}
{{ .Strategy }}
{{- end }}
  selector:
{{ .Selector }}
  template:
    metadata:
      labels:
{{ .PodLabels }}
{{- .PodAnnotations }}
    spec:
{{ .Spec }}`)

const selectorTempl = `%[1]s
{{- include "%[2]s.selectorLabels" . | nindent 6 }}
%[3]s`

// New creates processor for k8s Deployment resource.
func New() helmify.Processor {
	return &deployment{}
}

type deployment struct{}

// Process k8s Deployment object into template. Returns false if not capable of processing given resource type.
func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != deploymentGVC {
		return false, nil, nil
	}
	depl := appsv1.Deployment{}

	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &depl)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to deployment", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	values := helmify.Values{}

	name := appMeta.TrimName(obj.GetName())
	replicas, err := processReplicas(name, &depl, &values)
	if err != nil {
		return true, nil, err
	}

	revisionHistoryLimit, err := processRevisionHistoryLimit(name, &depl, &values)
	if err != nil {
		return true, nil, err
	}

	strategy, err := processStrategy(name, &depl, &values)
	if err != nil {
		return true, nil, err
	}

	matchLabels, err := yamlformat.Marshal(map[string]interface{}{"matchLabels": depl.Spec.Selector.MatchLabels}, 0)
	if err != nil {
		return true, nil, err
	}
	matchExpr := ""
	if depl.Spec.Selector.MatchExpressions != nil {
		matchExpr, err = yamlformat.Marshal(map[string]interface{}{"matchExpressions": depl.Spec.Selector.MatchExpressions}, 0)
		if err != nil {
			return true, nil, err
		}
	}
	selector := fmt.Sprintf(selectorTempl, matchLabels, appMeta.ChartName(), matchExpr)
	selector = strings.Trim(selector, " \n")
	selector = string(yamlformat.Indent([]byte(selector), 4))

	podLabels, err := yamlformat.Marshal(depl.Spec.Template.ObjectMeta.Labels, 8)
	if err != nil {
		return true, nil, err
	}
	podLabels += fmt.Sprintf("\n      {{- include \"%s.selectorLabels\" . | nindent 8 }}", appMeta.ChartName())

	podAnnotations := ""
	if len(depl.Spec.Template.ObjectMeta.Annotations) != 0 {
		podAnnotations, err = yamlformat.Marshal(map[string]interface{}{"annotations": depl.Spec.Template.ObjectMeta.Annotations}, 6)
		if err != nil {
			return true, nil, err
		}

		podAnnotations = "\n" + podAnnotations
	}

	nameCamel := strcase.ToLowerCamel(name)
	specMap, podValues, err := pod.ProcessSpec(nameCamel, appMeta, depl.Spec.Template.Spec)
	if err != nil {
		return true, nil, err
	}
	err = values.Merge(podValues)
	if err != nil {
		return true, nil, err
	}

	spec, err := yamlformat.Marshal(specMap, 6)
	if err != nil {
		return true, nil, err
	}
	if appMeta.Config().AddWebhookOption {
		spec = addWebhookOption(spec)
	}

	spec = replaceSingleQuotes(spec)

	return true, &result{
		values: values,
		data: struct {
			Meta                 string
			Replicas             string
			RevisionHistoryLimit string
			Strategy             string
			Selector             string
			PodLabels            string
			PodAnnotations       string
			Spec                 string
		}{
			Meta:                 meta,
			Replicas:             replicas,
			RevisionHistoryLimit: revisionHistoryLimit,
			Strategy:             strategy,
			Selector:             selector,
			PodLabels:            podLabels,
			PodAnnotations:       podAnnotations,
			Spec:                 spec,
		},
	}, nil
}

func replaceSingleQuotes(s string) string {
	r := regexp.MustCompile(`'({{((.*|.*\n.*))}}.*)'`)
	return r.ReplaceAllString(s, "${1}")
}

func addWebhookOption(manifest string) string {
	webhookOptionHeader := "      {{- if .Values.webhook.enabled }}"
	webhookOptionFooter := "      {{- end }}"
	volumes := `      - name: cert
        secret:
          defaultMode: 420
          secretName: webhook-server-cert`
	volumeMounts := `        - mountPath: /tmp/k8s-webhook-server/serving-certs
          name: cert
          readOnly: true`
	manifest = strings.ReplaceAll(manifest, volumes, fmt.Sprintf("%s\n%s\n%s",
		webhookOptionHeader, volumes, webhookOptionFooter))
	manifest = strings.ReplaceAll(manifest, volumeMounts, fmt.Sprintf("%s\n%s\n%s",
		webhookOptionHeader, volumeMounts, webhookOptionFooter))

	re := regexp.MustCompile(`        - containerPort: \d+
          name: webhook-server
          protocol: TCP`)

	manifest = re.ReplaceAllString(manifest, fmt.Sprintf("%s\n%s\n%s", webhookOptionHeader,
		re.FindString(manifest), webhookOptionFooter))
	return manifest
}

func processReplicas(name string, deployment *appsv1.Deployment, values *helmify.Values) (string, error) {
	if deployment.Spec.Replicas == nil {
		return "", nil
	}
	replicasTpl, err := values.Add(int64(*deployment.Spec.Replicas), name, "replicas")
	if err != nil {
		return "", err
	}
	replicas, err := yamlformat.Marshal(map[string]interface{}{"replicas": replicasTpl}, 2)
	if err != nil {
		return "", err
	}
	replicas = strings.ReplaceAll(replicas, "'", "")
	return replicas, nil
}

func processRevisionHistoryLimit(name string, deployment *appsv1.Deployment, values *helmify.Values) (string, error) {
	if deployment.Spec.RevisionHistoryLimit == nil {
		return "", nil
	}
	revisionHistoryLimitTpl, err := values.Add(int64(*deployment.Spec.RevisionHistoryLimit), name, "revisionHistoryLimit")
	if err != nil {
		return "", err
	}
	revisionHistoryLimit, err := yamlformat.Marshal(map[string]interface{}{"revisionHistoryLimit": revisionHistoryLimitTpl}, 2)
	if err != nil {
		return "", err
	}
	revisionHistoryLimit = strings.ReplaceAll(revisionHistoryLimit, "'", "")
	return revisionHistoryLimit, nil
}

func processStrategy(name string, deployment *appsv1.Deployment, values *helmify.Values) (string, error) {
	if deployment.Spec.Strategy.Type == "" {
		return "", nil
	}
	allowedStrategyTypes := map[appsv1.DeploymentStrategyType]bool{
		appsv1.RecreateDeploymentStrategyType:      true,
		appsv1.RollingUpdateDeploymentStrategyType: true,
	}
	if !allowedStrategyTypes[deployment.Spec.Strategy.Type] {
		return "", fmt.Errorf("invalid deployment strategy type: %s", deployment.Spec.Strategy.Type)
	}
	strategyTypeTpl, err := values.Add(string(deployment.Spec.Strategy.Type), name, "strategy", "type")
	if err != nil {
		return "", err
	}
	strategyMap := map[string]interface{}{
		"type": strategyTypeTpl,
	}
	if deployment.Spec.Strategy.Type == appsv1.RollingUpdateDeploymentStrategyType {
		if rollingUpdate := deployment.Spec.Strategy.RollingUpdate; rollingUpdate != nil {
			rollingUpdateMap := map[string]interface{}{}
			setRollingUpdateField := func(value *intstr.IntOrString, fieldName string) error {
				var tpl string
				var err error
				if value.Type == intstr.Int {
					tpl, err = values.Add(value.IntValue(), name, "strategy", "rollingUpdate", fieldName)
				} else {
					tpl, err = values.Add(value.String(), name, "strategy", "rollingUpdate", fieldName)
				}
				if err != nil {
					return err
				}
				rollingUpdateMap[fieldName] = tpl
				return nil
			}
			if rollingUpdate.MaxSurge != nil {
				if err := setRollingUpdateField(rollingUpdate.MaxSurge, "maxSurge"); err != nil {
					return "", err
				}
			}
			if rollingUpdate.MaxUnavailable != nil {
				if err := setRollingUpdateField(rollingUpdate.MaxUnavailable, "maxUnavailable"); err != nil {
					return "", err
				}
			}
			strategyMap["rollingUpdate"] = rollingUpdateMap
		}
	}
	strategy, err := yamlformat.Marshal(map[string]interface{}{"strategy": strategyMap}, 2)
	if err != nil {
		return "", err
	}
	strategy = strings.ReplaceAll(strategy, "'", "")
	return strategy, nil
}

type result struct {
	data struct {
		Meta                 string
		Replicas             string
		RevisionHistoryLimit string
		Strategy             string
		Selector             string
		PodLabels            string
		PodAnnotations       string
		Spec                 string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return "deployment.yaml"
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return deploymentTempl.Execute(writer, r.data)
}
07070100000071000081A400000000000000000000000167C8625900001302000000000000000000000000000000000000003B00000000helmify-0.4.18/pkg/processor/deployment/deployment_test.gopackage deployment

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const (
	strDepl = `apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager
  namespace: my-operator-system
spec:
  revisionHistoryLimit: 5
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      control-plane: controller-manager
  template:
    metadata:
      labels:
        control-plane: controller-manager
    spec:
      containers:
      - args:
        - --secure-listen-address=0.0.0.0:8443
        - --upstream=http://127.0.0.1:8080/
        - --logtostderr=true
        - --v=10
        image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
        name: kube-rbac-proxy
        ports:
        - containerPort: 8443
          name: https
      - args:
        - --health-probe-bind-address=:8081
        - --metrics-bind-address=127.0.0.1:8080
        - --leader-elect
        command:
        - /manager
        volumeMounts:
        - mountPath: /controller_manager_config.yaml
          name: manager-config
          subPath: controller_manager_config.yaml
        - name: secret-volume
          mountPath: /my.ca
        - name: sample-pv-storage
          mountPath: "/usr/share/nginx/html"
        env:
        - name: VAR1
          valueFrom:
            secretKeyRef:
              name: my-operator-secret-vars
              key: VAR1
        - name: VAR2
          valueFrom:
            configMapKeyRef:
              name: my-operator-configmap-vars
              key: VAR2
        - name: VAR3
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: VAR4
          valueFrom:
            resourceFieldRef:
              resource: limits.cpu
        - name: VAR5
          value: "123"
        - name: VAR6
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['app.kubernetes.io/something']
        image: controller:latest
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: manager
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: 100m
            memory: 30Mi
          requests:
            cpu: 100m
            memory: 20Mi
        securityContext:
          allowPrivilegeEscalation: false
      securityContext:
        runAsNonRoot: true
      serviceAccountName: my-operator-controller-manager
      terminationGracePeriodSeconds: 10
      volumes:
      - configMap:
          name: my-operator-manager-config
        name: manager-config
      - name: secret-volume
        secret:
          secretName: my-operator-secret-ca
      - name: sample-pv-storage
        persistentVolumeClaim:
          claimName: my-sample-pv-claim
`
)

func Test_deployment_Process(t *testing.T) {
	var testInstance deployment

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strDepl)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}

var singleQuotesTest = []struct {
	input    string
	expected string
}{
	{
		"{{ .Values.x }}",
		"{{ .Values.x }}",
	},
	{
		"'{{ .Values.x }}'",
		"{{ .Values.x }}",
	},
	{
		"'{{ .Values.x }}:{{ .Values.y }}'",
		"{{ .Values.x }}:{{ .Values.y }}",
	},
	{
		"'{{ .Values.x }}:{{ .Values.y \n\t| default .Chart.AppVersion}}'",
		"{{ .Values.x }}:{{ .Values.y \n\t| default .Chart.AppVersion}}",
	},
	{
		"echo 'x'",
		"echo 'x'",
	},
	{
		"abcd: x.y['x/y']",
		"abcd: x.y['x/y']",
	},
	{
		"abcd: x.y[\"'{{}}'\"]",
		"abcd: x.y[\"{{}}\"]",
	},
	{
		"image: '{{ .Values.x }}'",
		"image: {{ .Values.x }}",
	},
	{
		"'{{ .Values.x }} y'",
		"{{ .Values.x }} y",
	},
	{
		"\t\t- mountPath: './x.y'",
		"\t\t- mountPath: './x.y'",
	},
	{
		"'{{}}'",
		"{{}}",
	},
	{
		"'{{ {nested} }}'",
		"{{ {nested} }}",
	},
	{
		"'{{ '{{nested}}' }}'",
		"{{ '{{nested}}' }}",
	},
	{
		"'{{ unbalanced }'",
		"'{{ unbalanced }'",
	},
	{
		"'{{\nincomplete content'",
		"'{{\nincomplete content'",
	},
	{
		"'{{ @#$%^&*() }}'",
		"{{ @#$%^&*() }}",
	},
}

func Test_replaceSingleQuotes(t *testing.T) {
	for _, tt := range singleQuotesTest {
		t.Run(tt.input, func(t *testing.T) {
			s := replaceSingleQuotes(tt.input)
			if s != tt.expected {
				t.Errorf("got %q, want %q", s, tt.expected)
			}
		})
	}
}
07070100000072000081A400000000000000000000000167C8625900000063000000000000000000000000000000000000002400000000helmify-0.4.18/pkg/processor/doc.go// Package processor contains processors converting k8s objects to Helm template
package processor
07070100000073000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002100000000helmify-0.4.18/pkg/processor/job07070100000074000081A400000000000000000000000167C8625900000F7B000000000000000000000000000000000000002900000000helmify-0.4.18/pkg/processor/job/cron.gopackage job

import (
	"fmt"
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	"github.com/arttor/helmify/pkg/processor/pod"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	"io"
	batchv1 "k8s.io/api/batch/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"strings"
	"text/template"
)

var cronTempl, _ = template.New("cron").Parse(
	`{{ .Meta }}
{{ .Spec }}`)

var cronGVC = schema.GroupVersionKind{
	Group:   "batch",
	Version: "v1",
	Kind:    "CronJob",
}

// NewCron creates processor for k8s CronJob resource.
func NewCron() helmify.Processor {
	return &cron{}
}

type cron struct{}

// Process k8s CronJob object into template. Returns false if not capable of processing given resource type.
func (p cron) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != cronGVC {
		return false, nil, nil
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}
	name := appMeta.TrimName(obj.GetName())
	nameCamelCase := strcase.ToLowerCamel(name)

	jobObj := batchv1.CronJob{}
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &jobObj)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to Job", err)
	}
	spec := jobObj.Spec
	specMap, exists, err := unstructured.NestedMap(obj.Object, "spec")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to get job spec", err)
	}
	if !exists {
		return true, nil, fmt.Errorf("no job spec presented")
	}

	values := helmify.Values{}

	// process job spec params:
	if spec.Schedule != "" {
		err := templateSpecVal(spec.Schedule, &values, specMap, nameCamelCase, "schedule")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.Suspend != nil {
		err := templateSpecVal(*spec.Suspend, &values, specMap, nameCamelCase, "suspend")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.FailedJobsHistoryLimit != nil {
		err := templateSpecVal(*spec.FailedJobsHistoryLimit, &values, specMap, nameCamelCase, "failedJobsHistoryLimit")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.StartingDeadlineSeconds != nil {
		err := templateSpecVal(*spec.StartingDeadlineSeconds, &values, specMap, nameCamelCase, "startingDeadlineSeconds")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.TimeZone != nil {
		err := templateSpecVal(*spec.TimeZone, &values, specMap, nameCamelCase, "timeZone")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.SuccessfulJobsHistoryLimit != nil {
		err := templateSpecVal(*spec.SuccessfulJobsHistoryLimit, &values, specMap, nameCamelCase, "successfulJobsHistoryLimit")
		if err != nil {
			return true, nil, err
		}
	}

	// process job pod template:
	podSpecMap, podValues, err := pod.ProcessSpec(nameCamelCase, appMeta, jobObj.Spec.JobTemplate.Spec.Template.Spec)
	if err != nil {
		return true, nil, err
	}
	err = values.Merge(podValues)
	if err != nil {
		return true, nil, err
	}

	err = unstructured.SetNestedMap(specMap, podSpecMap, "jobTemplate", "spec", "template", "spec")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to template job spec", err)
	}

	specStr, err := yamlformat.Marshal(map[string]interface{}{"spec": specMap}, 0)
	if err != nil {
		return true, nil, err
	}
	specStr = strings.ReplaceAll(specStr, "'", "")

	return true, &resultCron{
		name: name + ".yaml",
		data: struct {
			Meta string
			Spec string
		}{Meta: meta, Spec: specStr},
		values: values,
	}, nil
}

type resultCron struct {
	name string
	data struct {
		Meta string
		Spec string
	}
	values helmify.Values
}

func (r *resultCron) Filename() string {
	return r.name
}

func (r *resultCron) Values() helmify.Values {
	return r.values
}

func (r *resultCron) Write(writer io.Writer) error {
	return cronTempl.Execute(writer, r.data)
}
07070100000075000081A400000000000000000000000167C8625900000449000000000000000000000000000000000000002E00000000helmify-0.4.18/pkg/processor/job/cron_test.gopackage job

import (
	"github.com/arttor/helmify/internal"
	"github.com/arttor/helmify/pkg/metadata"
	"github.com/stretchr/testify/assert"
	"testing"
)

const (
	strCron = `apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox:1.28
              imagePullPolicy: IfNotPresent
              command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure`
)

func Test_Cron_Process(t *testing.T) {
	var testInstance cron

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strCron)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000076000081A400000000000000000000000167C862590000112E000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/processor/job/job.gopackage job

import (
	"fmt"
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	"github.com/arttor/helmify/pkg/processor/pod"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	"io"
	batchv1 "k8s.io/api/batch/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"strings"
	"text/template"
)

var jobTempl, _ = template.New("job").Parse(
	`{{ .Meta }}
{{ .Spec }}`)

var jobGVC = schema.GroupVersionKind{
	Group:   "batch",
	Version: "v1",
	Kind:    "Job",
}

// NewJob creates processor for k8s Job resource.
func NewJob() helmify.Processor {
	return &job{}
}

type job struct{}

// Process k8s Job object into template. Returns false if not capable of processing given resource type.
func (p job) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != jobGVC {
		return false, nil, nil
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}
	name := appMeta.TrimName(obj.GetName())
	nameCamelCase := strcase.ToLowerCamel(name)

	jobObj := batchv1.Job{}
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &jobObj)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to Job", err)
	}
	spec := jobObj.Spec
	specMap, exists, err := unstructured.NestedMap(obj.Object, "spec")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to get job spec", err)
	}
	if !exists {
		return true, nil, fmt.Errorf("no job spec presented")
	}

	values := helmify.Values{}

	// process job spec params:
	if spec.BackoffLimit != nil {
		err := templateSpecVal(*spec.BackoffLimit, &values, specMap, nameCamelCase, "backoffLimit")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.ActiveDeadlineSeconds != nil {
		err := templateSpecVal(*spec.ActiveDeadlineSeconds, &values, specMap, nameCamelCase, "activeDeadlineSeconds")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.Completions != nil {
		err := templateSpecVal(*spec.Completions, &values, specMap, nameCamelCase, "completions")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.Parallelism != nil {
		err := templateSpecVal(*spec.Parallelism, &values, specMap, nameCamelCase, "parallelism")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.Suspend != nil {
		err := templateSpecVal(*spec.Suspend, &values, specMap, nameCamelCase, "suspend")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.ActiveDeadlineSeconds != nil {
		err := templateSpecVal(*spec.ActiveDeadlineSeconds, &values, specMap, nameCamelCase, "activeDeadlineSeconds")
		if err != nil {
			return true, nil, err
		}
	}
	// process job pod template:
	podSpecMap, podValues, err := pod.ProcessSpec(nameCamelCase, appMeta, jobObj.Spec.Template.Spec)
	if err != nil {
		return true, nil, err
	}
	err = values.Merge(podValues)
	if err != nil {
		return true, nil, err
	}

	err = unstructured.SetNestedMap(specMap, podSpecMap, "template", "spec")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to template job spec", err)
	}

	specStr, err := yamlformat.Marshal(map[string]interface{}{"spec": specMap}, 0)
	if err != nil {
		return true, nil, err
	}
	specStr = strings.ReplaceAll(specStr, "'", "")

	return true, &result{
		name: name + ".yaml",
		data: struct {
			Meta string
			Spec string
		}{Meta: meta, Spec: specStr},
		values: values,
	}, nil
}

type result struct {
	name string
	data struct {
		Meta string
		Spec string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return jobTempl.Execute(writer, r.data)
}

func templateSpecVal(val any, values *helmify.Values, specMap map[string]interface{}, objName string, fieldName ...string) error {
	valName := []string{objName}
	valName = append(valName, fieldName...)
	templatedVal, err := values.Add(val, valName...)
	if err != nil {
		return fmt.Errorf("%w: unable to set %q to values", err, strings.Join(valName, "."))
	}

	err = unstructured.SetNestedField(specMap, templatedVal, fieldName...)
	if err != nil {
		return fmt.Errorf("%w: unable to template job %q", err, strings.Join(valName, "."))
	}
	return nil
}
07070100000077000081A400000000000000000000000167C86259000003A0000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/processor/job/job_test.gopackage job

import (
	"github.com/arttor/helmify/internal"
	"github.com/arttor/helmify/pkg/metadata"
	"github.com/stretchr/testify/assert"
	"testing"
)

const (
	strJob = `apiVersion: batch/v1
kind: Job
metadata:
  name: batch-job
spec:
  template:
    spec:
      containers:
        - name: pi
          image: perl:5.34.0
          command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4`
)

func Test_configMap_Process(t *testing.T) {
	var testInstance job

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(strJob)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000078000081A400000000000000000000000167C8625900000B88000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/processor/meta.gopackage processor

import (
	"fmt"
	"strings"

	"github.com/iancoleman/strcase"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
)

const metaTemplate = `apiVersion: %[1]s
kind: %[2]s
metadata:
  name: %[3]s
%[7]s
  labels:
%[5]s
  {{- include "%[4]s.labels" . | nindent 4 }}
%[6]s`

const annotationsTemplate = `  annotations:
    {{- toYaml .Values.%[1]s.%[2]s.annotations | nindent 4 }}`

type MetaOpt interface {
	apply(*options)
}

type options struct {
	values      helmify.Values
	annotations bool
}

type annotationsOption struct {
	values helmify.Values
}

func (a annotationsOption) apply(opts *options) {
	opts.annotations = true
	opts.values = a.values
}

func WithAnnotations(values helmify.Values) MetaOpt {
	return annotationsOption{
		values: values,
	}
}

// ProcessObjMeta - returns object apiVersion, kind and metadata as helm template.
func ProcessObjMeta(appMeta helmify.AppMetadata, obj *unstructured.Unstructured, opts ...MetaOpt) (string, error) {
	options := &options{}
	for _, opt := range opts {
		opt.apply(options)
	}

	var err error
	var labels, annotations, namespace string
	if len(obj.GetLabels()) != 0 {
		l := obj.GetLabels()
		// provided by Helm
		delete(l, "app.kubernetes.io/name")
		delete(l, "app.kubernetes.io/instance")
		delete(l, "app.kubernetes.io/version")
		delete(l, "app.kubernetes.io/managed-by")
		delete(l, "helm.sh/chart")

		// Since we delete labels above, it is possible that at this point there are no more labels.
		if len(l) > 0 {
			labels, err = yamlformat.Marshal(l, 4)
			if err != nil {
				return "", err
			}
		}
	}
	if len(obj.GetAnnotations()) != 0 {
		annotations, err = yamlformat.Marshal(map[string]interface{}{"annotations": obj.GetAnnotations()}, 2)
		if err != nil {
			return "", err
		}
	}

	if (obj.GetNamespace() != "") && (appMeta.Config().PreserveNs) {
		namespace, err = yamlformat.Marshal(map[string]interface{}{"namespace": obj.GetNamespace()}, 2)
		if err != nil {
			return "", err
		}
	}

	templatedName := appMeta.TemplatedName(obj.GetName())
	apiVersion, kind := obj.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind()

	var metaStr string
	if options.values != nil && options.annotations {
		name := strcase.ToLowerCamel(appMeta.TrimName(obj.GetName()))
		kind := strcase.ToLowerCamel(kind)
		valuesAnnotations := make(map[string]interface{})
		for k, v := range obj.GetAnnotations() {
			valuesAnnotations[k] = v
		}
		err = unstructured.SetNestedField(options.values, valuesAnnotations, name, kind, "annotations")
		if err != nil {
			return "", err
		}

		annotations = fmt.Sprintf(annotationsTemplate, name, kind)
	}

	metaStr = fmt.Sprintf(metaTemplate, apiVersion, kind, templatedName, appMeta.ChartName(), labels, annotations, namespace)
	metaStr = strings.Trim(metaStr, " \n")
	metaStr = strings.ReplaceAll(metaStr, "\n\n", "\n")
	return metaStr, nil
}
07070100000079000081A400000000000000000000000167C8625900000202000000000000000000000000000000000000002A00000000helmify-0.4.18/pkg/processor/meta_test.gopackage processor

import (
	"github.com/arttor/helmify/pkg/config"
	"testing"

	"github.com/arttor/helmify/internal"
	"github.com/arttor/helmify/pkg/metadata"
	"github.com/stretchr/testify/assert"
)

func TestProcessObjMeta(t *testing.T) {
	testMeta := metadata.New(config.Config{ChartName: "chart-name"})
	testMeta.Load(internal.TestNs)
	res, err := ProcessObjMeta(testMeta, internal.TestNs)
	assert.NoError(t, err)
	assert.Contains(t, res, "chart-name.labels")
	assert.Contains(t, res, "chart-name.fullname")
}
0707010000007A000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002100000000helmify-0.4.18/pkg/processor/pod0707010000007B000081A400000000000000000000000167C862590000245B000000000000000000000000000000000000002800000000helmify-0.4.18/pkg/processor/pod/pod.gopackage pod

import (
	"fmt"
	"strings"

	"github.com/arttor/helmify/pkg/cluster"
	"github.com/arttor/helmify/pkg/helmify"
	securityContext "github.com/arttor/helmify/pkg/processor/security-context"
	"github.com/iancoleman/strcase"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
)

const imagePullPolicyTemplate = "{{ .Values.%[1]s.%[2]s.imagePullPolicy }}"
const envValue = "{{ quote .Values.%[1]s.%[2]s.%[3]s.%[4]s }}"

func ProcessSpec(objName string, appMeta helmify.AppMetadata, spec corev1.PodSpec) (map[string]interface{}, helmify.Values, error) {
	values, err := processPodSpec(objName, appMeta, &spec)
	if err != nil {
		return nil, nil, err
	}

	// replace PVC to templated name
	for i := 0; i < len(spec.Volumes); i++ {
		vol := spec.Volumes[i]
		if vol.PersistentVolumeClaim == nil {
			continue
		}
		tempPVCName := appMeta.TemplatedName(vol.PersistentVolumeClaim.ClaimName)

		spec.Volumes[i].PersistentVolumeClaim.ClaimName = tempPVCName
	}

	// replace container resources with template to values.
	specMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&spec)
	if err != nil {
		return nil, nil, fmt.Errorf("%w: unable to convert podSpec to map", err)
	}

	specMap, values, err = processNestedContainers(specMap, objName, values, "containers")
	if err != nil {
		return nil, nil, err
	}

	specMap, values, err = processNestedContainers(specMap, objName, values, "initContainers")
	if err != nil {
		return nil, nil, err
	}

	if appMeta.Config().ImagePullSecrets {
		if _, defined := specMap["imagePullSecrets"]; !defined {
			specMap["imagePullSecrets"] = "{{ .Values.imagePullSecrets | default list | toJson }}"
			values["imagePullSecrets"] = []string{}
		}
	}

	err = securityContext.ProcessContainerSecurityContext(objName, specMap, &values)
	if err != nil {
		return nil, nil, err
	}
	if spec.SecurityContext != nil {
		securityContextMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&spec.SecurityContext)
		if err != nil {
			return nil, nil, err
		}
		if len(securityContextMap) > 0 {
			err = unstructured.SetNestedField(specMap, fmt.Sprintf(`{{- toYaml .Values.%[1]s.podSecurityContext | nindent 8 }}`, objName), "securityContext")
			if err != nil {
				return nil, nil, err
			}

			err = unstructured.SetNestedField(values, securityContextMap, objName, "podSecurityContext")
			if err != nil {
				return nil, nil, fmt.Errorf("%w: unable to set deployment value field", err)
			}
		}
	}

	// process nodeSelector if presented:
	if spec.NodeSelector != nil {
		err = unstructured.SetNestedField(specMap, fmt.Sprintf(`{{- toYaml .Values.%s.nodeSelector | nindent 8 }}`, objName), "nodeSelector")
		if err != nil {
			return nil, nil, err
		}
		err = unstructured.SetNestedStringMap(values, spec.NodeSelector, objName, "nodeSelector")
		if err != nil {
			return nil, nil, err
		}
	}

	return specMap, values, nil
}

func processNestedContainers(specMap map[string]interface{}, objName string, values map[string]interface{}, containerKey string) (map[string]interface{}, map[string]interface{}, error) {
	containers, _, err := unstructured.NestedSlice(specMap, containerKey)
	if err != nil {
		return nil, nil, err
	}

	if len(containers) > 0 {
		containers, values, err = processContainers(objName, values, containerKey, containers)
		if err != nil {
			return nil, nil, err
		}

		err = unstructured.SetNestedSlice(specMap, containers, containerKey)
		if err != nil {
			return nil, nil, err
		}
	}

	return specMap, values, nil
}

func processContainers(objName string, values helmify.Values, containerType string, containers []interface{}) ([]interface{}, helmify.Values, error) {
	for i := range containers {
		containerName := strcase.ToLowerCamel((containers[i].(map[string]interface{})["name"]).(string))
		res, exists, err := unstructured.NestedMap(values, objName, containerName, "resources")
		if err != nil {
			return nil, nil, err
		}
		if exists && len(res) > 0 {
			err = unstructured.SetNestedField(containers[i].(map[string]interface{}), fmt.Sprintf(`{{- toYaml .Values.%s.%s.resources | nindent 10 }}`, objName, containerName), "resources")
			if err != nil {
				return nil, nil, err
			}
		}

		args, exists, err := unstructured.NestedStringSlice(containers[i].(map[string]interface{}), "args")
		if err != nil {
			return nil, nil, err
		}
		if exists && len(args) > 0 {
			err = unstructured.SetNestedField(containers[i].(map[string]interface{}), fmt.Sprintf(`{{- toYaml .Values.%[1]s.%[2]s.args | nindent 8 }}`, objName, containerName), "args")
			if err != nil {
				return nil, nil, err
			}

			err = unstructured.SetNestedStringSlice(values, args, objName, containerName, "args")
			if err != nil {
				return nil, nil, fmt.Errorf("%w: unable to set deployment value field", err)
			}
		}
	}
	return containers, values, nil
}

func processPodSpec(name string, appMeta helmify.AppMetadata, pod *corev1.PodSpec) (helmify.Values, error) {
	values := helmify.Values{}
	for i, c := range pod.Containers {
		processed, err := processPodContainer(name, appMeta, c, &values)
		if err != nil {
			return nil, err
		}
		pod.Containers[i] = processed
	}

	for i, c := range pod.InitContainers {
		processed, err := processPodContainer(name, appMeta, c, &values)
		if err != nil {
			return nil, err
		}
		pod.InitContainers[i] = processed
	}

	for _, v := range pod.Volumes {
		if v.ConfigMap != nil {
			v.ConfigMap.Name = appMeta.TemplatedName(v.ConfigMap.Name)
		}
		if v.Secret != nil {
			v.Secret.SecretName = appMeta.TemplatedName(v.Secret.SecretName)
		}
	}
	pod.ServiceAccountName = appMeta.TemplatedName(pod.ServiceAccountName)

	for i, s := range pod.ImagePullSecrets {
		pod.ImagePullSecrets[i].Name = appMeta.TemplatedName(s.Name)
	}

	return values, nil
}

func processPodContainer(name string, appMeta helmify.AppMetadata, c corev1.Container, values *helmify.Values) (corev1.Container, error) {
	index := strings.LastIndex(c.Image, ":")
	if strings.Contains(c.Image, "@") && strings.Count(c.Image, ":") >= 2 {
		last := strings.LastIndex(c.Image, ":")
		index = strings.LastIndex(c.Image[:last], ":")
	}
	if index < 0 {
		return c, fmt.Errorf("wrong image format: %q", c.Image)
	}
	repo, tag := c.Image[:index], c.Image[index+1:]
	containerName := strcase.ToLowerCamel(c.Name)
	c.Image = fmt.Sprintf("{{ .Values.%[1]s.%[2]s.image.repository }}:{{ .Values.%[1]s.%[2]s.image.tag | default .Chart.AppVersion }}", name, containerName)

	err := unstructured.SetNestedField(*values, repo, name, containerName, "image", "repository")
	if err != nil {
		return c, fmt.Errorf("%w: unable to set deployment value field", err)
	}
	err = unstructured.SetNestedField(*values, tag, name, containerName, "image", "tag")
	if err != nil {
		return c, fmt.Errorf("%w: unable to set deployment value field", err)
	}

	c, err = processEnv(name, appMeta, c, values)
	if err != nil {
		return c, err
	}

	for _, e := range c.EnvFrom {
		if e.SecretRef != nil {
			e.SecretRef.Name = appMeta.TemplatedName(e.SecretRef.Name)
		}
		if e.ConfigMapRef != nil {
			e.ConfigMapRef.Name = appMeta.TemplatedName(e.ConfigMapRef.Name)
		}
	}
	c.Env = append(c.Env, corev1.EnvVar{
		Name:  cluster.DomainEnv,
		Value: fmt.Sprintf("{{ quote .Values.%s }}", cluster.DomainKey),
	})
	for k, v := range c.Resources.Requests {
		err = unstructured.SetNestedField(*values, v.ToUnstructured(), name, containerName, "resources", "requests", k.String())
		if err != nil {
			return c, fmt.Errorf("%w: unable to set container resources value", err)
		}
	}
	for k, v := range c.Resources.Limits {
		err = unstructured.SetNestedField(*values, v.ToUnstructured(), name, containerName, "resources", "limits", k.String())
		if err != nil {
			return c, fmt.Errorf("%w: unable to set container resources value", err)
		}
	}

	if c.ImagePullPolicy != "" {
		err = unstructured.SetNestedField(*values, string(c.ImagePullPolicy), name, containerName, "imagePullPolicy")
		if err != nil {
			return c, fmt.Errorf("%w: unable to set container imagePullPolicy", err)
		}
		c.ImagePullPolicy = corev1.PullPolicy(fmt.Sprintf(imagePullPolicyTemplate, name, containerName))
	}
	return c, nil
}

func processEnv(name string, appMeta helmify.AppMetadata, c corev1.Container, values *helmify.Values) (corev1.Container, error) {
	containerName := strcase.ToLowerCamel(c.Name)
	for i := 0; i < len(c.Env); i++ {
		if c.Env[i].ValueFrom != nil {
			switch {
			case c.Env[i].ValueFrom.SecretKeyRef != nil:
				c.Env[i].ValueFrom.SecretKeyRef.Name = appMeta.TemplatedName(c.Env[i].ValueFrom.SecretKeyRef.Name)
			case c.Env[i].ValueFrom.ConfigMapKeyRef != nil:
				c.Env[i].ValueFrom.ConfigMapKeyRef.Name = appMeta.TemplatedName(c.Env[i].ValueFrom.ConfigMapKeyRef.Name)
			case c.Env[i].ValueFrom.FieldRef != nil, c.Env[i].ValueFrom.ResourceFieldRef != nil:
				// nothing to change here, keep the original value
			}
			continue
		}

		err := unstructured.SetNestedField(*values, c.Env[i].Value, name, containerName, "env", strcase.ToLowerCamel(strings.ToLower(c.Env[i].Name)))
		if err != nil {
			return c, fmt.Errorf("%w: unable to set deployment value field", err)
		}
		c.Env[i].Value = fmt.Sprintf(envValue, name, containerName, "env", strcase.ToLowerCamel(strings.ToLower(c.Env[i].Name)))
	}
	return c, nil
}
0707010000007C000081A400000000000000000000000167C862590000228E000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/processor/pod/pod_test.gopackage pod

import (
	"testing"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/metadata"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/apimachinery/pkg/runtime"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const (
	strDeployment = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        args:
        - --test
        - --arg
        ports:
        - containerPort: 80
`

	strDeploymentWithTagAndDigest = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229
        ports:
        - containerPort: 80
`

	strDeploymentWithNoArgs = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
`

	strDeploymentWithPort = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: localhost:6001/my_project:latest
        ports:
        - containerPort: 80
`
	strDeploymentWithPodSecurityContext = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: localhost:6001/my_project:latest
      securityContext:
        fsGroup: 20000
        runAsGroup: 30000
        runAsNonRoot: true
        runAsUser: 65532

`
)

func Test_pod_Process(t *testing.T) {
	t.Run("deployment with args", func(t *testing.T) {
		var deploy appsv1.Deployment
		obj := internal.GenerateObj(strDeployment)
		err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &deploy)
		specMap, tmpl, err := ProcessSpec("nginx", &metadata.Service{}, deploy.Spec.Template.Spec)
		assert.NoError(t, err)

		assert.Equal(t, map[string]interface{}{
			"containers": []interface{}{
				map[string]interface{}{
					"args": "{{- toYaml .Values.nginx.nginx.args | nindent 8 }}",
					"env": []interface{}{
						map[string]interface{}{
							"name":  "KUBERNETES_CLUSTER_DOMAIN",
							"value": "{{ quote .Values.kubernetesClusterDomain }}",
						},
					},
					"image": "{{ .Values.nginx.nginx.image.repository }}:{{ .Values.nginx.nginx.image.tag | default .Chart.AppVersion }}",
					"name":  "nginx", "ports": []interface{}{
						map[string]interface{}{
							"containerPort": int64(80),
						},
					},
					"resources": map[string]interface{}{},
				},
			},
		}, specMap)

		assert.Equal(t, helmify.Values{
			"nginx": map[string]interface{}{
				"nginx": map[string]interface{}{
					"image": map[string]interface{}{
						"repository": "nginx",
						"tag":        "1.14.2",
					},
					"args": []interface{}{
						"--test",
						"--arg",
					},
				},
			},
		}, tmpl)
	})

	t.Run("deployment with no args", func(t *testing.T) {
		var deploy appsv1.Deployment
		obj := internal.GenerateObj(strDeploymentWithNoArgs)
		err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &deploy)
		specMap, tmpl, err := ProcessSpec("nginx", &metadata.Service{}, deploy.Spec.Template.Spec)
		assert.NoError(t, err)

		assert.Equal(t, map[string]interface{}{
			"containers": []interface{}{
				map[string]interface{}{
					"env": []interface{}{
						map[string]interface{}{
							"name":  "KUBERNETES_CLUSTER_DOMAIN",
							"value": "{{ quote .Values.kubernetesClusterDomain }}",
						},
					},
					"image": "{{ .Values.nginx.nginx.image.repository }}:{{ .Values.nginx.nginx.image.tag | default .Chart.AppVersion }}",
					"name":  "nginx", "ports": []interface{}{
						map[string]interface{}{
							"containerPort": int64(80),
						},
					},
					"resources": map[string]interface{}{},
				},
			},
		}, specMap)

		assert.Equal(t, helmify.Values{
			"nginx": map[string]interface{}{
				"nginx": map[string]interface{}{
					"image": map[string]interface{}{
						"repository": "nginx",
						"tag":        "1.14.2",
					},
				},
			},
		}, tmpl)
	})

	t.Run("deployment with image tag and digest", func(t *testing.T) {
		var deploy appsv1.Deployment
		obj := internal.GenerateObj(strDeploymentWithTagAndDigest)
		err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &deploy)
		specMap, tmpl, err := ProcessSpec("nginx", &metadata.Service{}, deploy.Spec.Template.Spec)
		assert.NoError(t, err)

		assert.Equal(t, map[string]interface{}{
			"containers": []interface{}{
				map[string]interface{}{
					"env": []interface{}{
						map[string]interface{}{
							"name":  "KUBERNETES_CLUSTER_DOMAIN",
							"value": "{{ quote .Values.kubernetesClusterDomain }}",
						},
					},
					"image": "{{ .Values.nginx.nginx.image.repository }}:{{ .Values.nginx.nginx.image.tag | default .Chart.AppVersion }}",
					"name":  "nginx", "ports": []interface{}{
						map[string]interface{}{
							"containerPort": int64(80),
						},
					},
					"resources": map[string]interface{}{},
				},
			},
		}, specMap)

		assert.Equal(t, helmify.Values{
			"nginx": map[string]interface{}{
				"nginx": map[string]interface{}{
					"image": map[string]interface{}{
						"repository": "nginx",
						"tag":        "1.14.2@sha256:cb5c1bddd1b5665e1867a7fa1b5fa843a47ee433bbb75d4293888b71def53229",
					},
				},
			},
		}, tmpl)
	})

	t.Run("deployment with image tag and port", func(t *testing.T) {
		var deploy appsv1.Deployment
		obj := internal.GenerateObj(strDeploymentWithPort)
		err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &deploy)
		specMap, tmpl, err := ProcessSpec("nginx", &metadata.Service{}, deploy.Spec.Template.Spec)
		assert.NoError(t, err)

		assert.Equal(t, map[string]interface{}{
			"containers": []interface{}{
				map[string]interface{}{
					"env": []interface{}{
						map[string]interface{}{
							"name":  "KUBERNETES_CLUSTER_DOMAIN",
							"value": "{{ quote .Values.kubernetesClusterDomain }}",
						},
					},
					"image": "{{ .Values.nginx.nginx.image.repository }}:{{ .Values.nginx.nginx.image.tag | default .Chart.AppVersion }}",
					"name":  "nginx", "ports": []interface{}{
						map[string]interface{}{
							"containerPort": int64(80),
						},
					},
					"resources": map[string]interface{}{},
				},
			},
		}, specMap)

		assert.Equal(t, helmify.Values{
			"nginx": map[string]interface{}{
				"nginx": map[string]interface{}{
					"image": map[string]interface{}{
						"repository": "localhost:6001/my_project",
						"tag":        "latest",
					},
				},
			},
		}, tmpl)
	})
	t.Run("deployment with securityContext", func(t *testing.T) {
		var deploy appsv1.Deployment
		obj := internal.GenerateObj(strDeploymentWithPodSecurityContext)
		err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &deploy)
		specMap, tmpl, err := ProcessSpec("nginx", &metadata.Service{}, deploy.Spec.Template.Spec)
		assert.NoError(t, err)
		assert.Equal(t, map[string]interface{}{
			"containers": []interface{}{
				map[string]interface{}{
					"env": []interface{}{
						map[string]interface{}{
							"name":  "KUBERNETES_CLUSTER_DOMAIN",
							"value": "{{ quote .Values.kubernetesClusterDomain }}",
						},
					},
					"image":     "{{ .Values.nginx.nginx.image.repository }}:{{ .Values.nginx.nginx.image.tag | default .Chart.AppVersion }}",
					"name":      "nginx",
					"resources": map[string]interface{}{},
				},
			},
			"securityContext": "{{- toYaml .Values.nginx.podSecurityContext | nindent 8 }}",
		}, specMap)

		assert.Equal(t, helmify.Values{
			"nginx": map[string]interface{}{
				"podSecurityContext": map[string]interface{}{
					"fsGroup":      int64(20000),
					"runAsGroup":   int64(30000),
					"runAsNonRoot": true,
					"runAsUser":    int64(65532),
				},
				"nginx": map[string]interface{}{
					"image": map[string]interface{}{
						"repository": "localhost:6001/my_project",
						"tag":        "latest",
					},
				},
			},
		}, tmpl)
	})

}
0707010000007D000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000003100000000helmify-0.4.18/pkg/processor/poddisruptionbudget0707010000007E000081A400000000000000000000000167C86259000009D6000000000000000000000000000000000000003800000000helmify-0.4.18/pkg/processor/poddisruptionbudget/pdb.gopackage poddisruptionbudget

import (
	"bytes"
	"fmt"
	"io"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	policyv1 "k8s.io/api/policy/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"
)

const (
	pdbTempSpec = `
spec:
  minAvailable: {{ .Values.%[1]s.minAvailable }}
  maxUnavailable: {{ .Values.%[1]s.maxUnavailable }}
  selector:
%[2]s
    {{- include "%[3]s.selectorLabels" . | nindent 6 }}`
)

var pdbGVC = schema.GroupVersionKind{
	Group:   "policy",
	Version: "v1",
	Kind:    "PodDisruptionBudget",
}

// New creates processor for k8s Service resource.
func New() helmify.Processor {
	return &pdb{}
}

type pdb struct{}

// Process k8s Service object into template. Returns false if not capable of processing given resource type.
func (r pdb) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != pdbGVC {
		return false, nil, nil
	}
	pdb := policyv1.PodDisruptionBudget{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &pdb)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to pdb", err)
	}
	spec := pdb.Spec
	values := helmify.Values{}

	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	name := appMeta.TrimName(obj.GetName())
	nameCamel := strcase.ToLowerCamel(name)

	selector, _ := yaml.Marshal(pdb.Spec.Selector)
	selector = yamlformat.Indent(selector, 4)
	selector = bytes.TrimRight(selector, "\n ")

	if spec.MaxUnavailable != nil {
		_, err := values.Add(spec.MaxUnavailable.IntValue(), nameCamel, "maxUnavailable")
		if err != nil {
			return true, nil, err
		}
	}

	if spec.MinAvailable != nil {
		_, err := values.Add(spec.MinAvailable.IntValue(), nameCamel, "minAvailable")
		if err != nil {
			return true, nil, err
		}
	}

	res := meta + fmt.Sprintf(pdbTempSpec, nameCamel, selector, appMeta.ChartName())
	return true, &result{
		name:   name,
		data:   res,
		values: values,
	}, nil
}

type result struct {
	name   string
	data   string
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name + ".yaml"
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	_, err := writer.Write([]byte(r.data))
	return err
}
0707010000007F000081A400000000000000000000000167C86259000003CE000000000000000000000000000000000000003D00000000helmify-0.4.18/pkg/processor/poddisruptionbudget/pdb_test.gopackage poddisruptionbudget

import (
	"os"
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const pdbYaml = `apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager-pdb
  namespace: my-operator-system
spec:
  minAvailable: 2
  selector:
    matchLabels:
      control-plane: controller-manager`

func Test_pdb_Process(t *testing.T) {
	var testInstance pdb

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(pdbYaml)
		processed, tt, err := testInstance.Process(&metadata.Service{}, obj)
		_ = tt.Write(os.Stdout)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000080000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002200000000helmify-0.4.18/pkg/processor/rbac07070100000081000081A400000000000000000000000167C86259000009FB000000000000000000000000000000000000003800000000helmify-0.4.18/pkg/processor/rbac/clusterrolebinding.gopackage rbac

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var clusterRoleBindingTempl, _ = template.New("clusterRoleBinding").Parse(
	`{{ .Meta }}
{{ .RoleRef }}
{{ .Subjects }}`)

var clusterRoleBindingGVC = schema.GroupVersionKind{
	Group:   "rbac.authorization.k8s.io",
	Version: "v1",
	Kind:    "ClusterRoleBinding",
}

// ClusterRoleBinding creates processor for k8s ClusterRoleBinding resource.
func ClusterRoleBinding() helmify.Processor {
	return &clusterRoleBinding{}
}

type clusterRoleBinding struct{}

// Process k8s ClusterRoleBinding object into template. Returns false if not capable of processing given resource type.
func (r clusterRoleBinding) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != clusterRoleBindingGVC {
		return false, nil, nil
	}

	rb := rbacv1.ClusterRoleBinding{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &rb)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to RoleBinding", err)
	}

	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	rb.RoleRef.Name = appMeta.TemplatedName(rb.RoleRef.Name)

	roleRef, err := yamlformat.Marshal(map[string]interface{}{"roleRef": &rb.RoleRef}, 0)
	if err != nil {
		return true, nil, err
	}

	for i, s := range rb.Subjects {
		s.Namespace = "{{ .Release.Namespace }}"
		s.Name = appMeta.TemplatedName(s.Name)
		rb.Subjects[i] = s
	}
	subjects, err := yamlformat.Marshal(map[string]interface{}{"subjects": &rb.Subjects}, 0)
	if err != nil {
		return true, nil, err
	}

	return true, &crbResult{
		name: appMeta.TrimName(obj.GetName()),
		data: struct {
			Meta     string
			RoleRef  string
			Subjects string
		}{
			Meta:     meta,
			RoleRef:  roleRef,
			Subjects: subjects,
		},
	}, nil
}

type crbResult struct {
	name string
	data struct {
		Meta     string
		RoleRef  string
		Subjects string
	}
}

func (r *crbResult) Filename() string {
	return strings.TrimSuffix(r.name, "-rolebinding") + "-rbac.yaml"
}

func (r *crbResult) Values() helmify.Values {
	return helmify.Values{}
}

func (r *crbResult) Write(writer io.Writer) error {
	return clusterRoleBindingTempl.Execute(writer, r.data)
}
07070100000082000081A400000000000000000000000167C8625900000408000000000000000000000000000000000000003D00000000helmify-0.4.18/pkg/processor/rbac/clusterrolebinding_test.gopackage rbac

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const clusterRoleBindingYaml = `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-operator-manager-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: my-operator-manager-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system`

func Test_clusterRoleBinding_Process(t *testing.T) {
	var testInstance clusterRoleBinding

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(clusterRoleBindingYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000083000081A400000000000000000000000167C8625900000A65000000000000000000000000000000000000002A00000000helmify-0.4.18/pkg/processor/rbac/role.gopackage rbac

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var roleTempl, _ = template.New("clusterRole").Parse(
	`{{ .Meta }}
{{- if .AggregationRule }}
{{ .AggregationRule }}
{{- end}}
{{ .Rules }}`)

var clusterRoleGVC = schema.GroupVersionKind{
	Group:   "rbac.authorization.k8s.io",
	Version: "v1",
	Kind:    "ClusterRole",
}
var roleGVC = schema.GroupVersionKind{
	Group:   "rbac.authorization.k8s.io",
	Version: "v1",
	Kind:    "Role",
}

// Role creates processor for k8s Role and ClusterRole resources.
func Role() helmify.Processor {
	return &role{}
}

type role struct{}

// Process k8s ClusterRole object into template. Returns false if not capable of processing given resource type.
func (r role) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	var aggregationRule string

	if obj.GroupVersionKind() != clusterRoleGVC && obj.GroupVersionKind() != roleGVC {
		return false, nil, nil
	}

	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	if existingAggRule := obj.Object["aggregationRule"]; existingAggRule != nil {
		if obj.GroupVersionKind().Kind == "Role" {
			return true, nil, fmt.Errorf("unable to set aggregationRule to the kind Role in %q: unsupported", obj.GetName())
		}

		if existingAggRule.(map[string]interface{})["clusterRoleSelectors"] != nil {
			aggRuleMap := map[string]interface{}{"aggregationRule": existingAggRule}

			aggregationRule, err = yamlformat.Marshal(aggRuleMap, 0)
			if err != nil {
				return true, nil, err
			}
		}
	}

	rules, err := yamlformat.Marshal(map[string]interface{}{"rules": obj.Object["rules"]}, 0)
	if err != nil {
		return true, nil, err
	}

	return true, &crResult{
		name: appMeta.TrimName(obj.GetName()),
		data: struct {
			Meta            string
			AggregationRule string
			Rules           string
		}{Meta: meta, AggregationRule: aggregationRule, Rules: rules},
	}, nil
}

type crResult struct {
	name string
	data struct {
		Meta            string
		AggregationRule string
		Rules           string
	}
}

func (r *crResult) Filename() string {
	return strings.TrimSuffix(r.name, "-role") + "-rbac.yaml"
}

func (r *crResult) GVK() schema.GroupVersionKind {
	return clusterRoleGVC
}

func (r *crResult) Values() helmify.Values {
	return helmify.Values{}
}

func (r *crResult) Write(writer io.Writer) error {
	return roleTempl.Execute(writer, r.data)
}
07070100000084000081A400000000000000000000000167C86259000003E9000000000000000000000000000000000000002F00000000helmify-0.4.18/pkg/processor/rbac/role_test.gopackage rbac

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const clusterRoleYaml = `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: my-operator-manager-role
aggregationRule:
  clusterRoleSelectors:
  - matchExpressions:
    - key: my.operator.dev/release
      operator: Exists
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list`

func Test_clusterRole_Process(t *testing.T) {
	var testInstance role

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(clusterRoleYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000085000081A400000000000000000000000167C8625900000998000000000000000000000000000000000000003100000000helmify-0.4.18/pkg/processor/rbac/rolebinding.gopackage rbac

import (
	"fmt"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	rbacv1 "k8s.io/api/rbac/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var roleBindingTempl, _ = template.New("roleBinding").Parse(
	`{{- .Meta }}
{{ .RoleRef }}
{{ .Subjects }}`)

var roleBindingGVC = schema.GroupVersionKind{
	Group:   "rbac.authorization.k8s.io",
	Version: "v1",
	Kind:    "RoleBinding",
}

// RoleBinding creates processor for k8s RoleBinding resource.
func RoleBinding() helmify.Processor {
	return &roleBinding{}
}

type roleBinding struct{}

// Process k8s RoleBinding object into helm template. Returns false if not capable of processing given resource type.
func (r roleBinding) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != roleBindingGVC {
		return false, nil, nil
	}
	rb := rbacv1.RoleBinding{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &rb)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to RoleBinding", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	rb.RoleRef.Name = appMeta.TemplatedName(rb.RoleRef.Name)

	roleRef, err := yamlformat.Marshal(map[string]interface{}{"roleRef": &rb.RoleRef}, 0)
	if err != nil {
		return true, nil, err
	}

	for i, s := range rb.Subjects {
		s.Namespace = "{{ .Release.Namespace }}"
		s.Name = appMeta.TemplatedName(s.Name)
		rb.Subjects[i] = s
	}
	subjects, err := yamlformat.Marshal(map[string]interface{}{"subjects": &rb.Subjects}, 0)
	if err != nil {
		return true, nil, err
	}

	return true, &rbResult{
		name: appMeta.TrimName(obj.GetName()),
		data: struct {
			Meta     string
			RoleRef  string
			Subjects string
		}{
			Meta:     meta,
			RoleRef:  roleRef,
			Subjects: subjects,
		},
	}, nil
}

type rbResult struct {
	name string
	data struct {
		Meta     string
		RoleRef  string
		Subjects string
	}
}

func (r *rbResult) Filename() string {
	return strings.TrimSuffix(r.name, "-rolebinding") + "-rbac.yaml"
}

func (r *rbResult) Values() helmify.Values {
	return helmify.Values{}
}

func (r *rbResult) Write(writer io.Writer) error {
	return roleBindingTempl.Execute(writer, r.data)
}
07070100000086000081A400000000000000000000000167C862590000040E000000000000000000000000000000000000003600000000helmify-0.4.18/pkg/processor/rbac/rolebinding_test.gopackage rbac

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const roleBindingYaml = `apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-operator-leader-election-rolebinding
  namespace: my-operator-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: my-operator-leader-election-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system`

func Test_roleBinding_Process(t *testing.T) {
	var testInstance roleBinding

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(roleBindingYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000087000081A400000000000000000000000167C862590000054B000000000000000000000000000000000000003400000000helmify-0.4.18/pkg/processor/rbac/serviceaccount.gopackage rbac

import (
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	"io"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var serviceAccountGVC = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "ServiceAccount",
}

// ServiceAccount creates processor for k8s ServiceAccount resource.
func ServiceAccount() helmify.Processor {
	return &serviceAccount{}
}

type serviceAccount struct{}

// Process k8s ServiceAccount object into helm template. Returns false if not capable of processing given resource type.
func (sa serviceAccount) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != serviceAccountGVC {
		return false, nil, nil
	}
	values := helmify.Values{}
	meta, err := processor.ProcessObjMeta(appMeta, obj, processor.WithAnnotations(values))
	if err != nil {
		return true, nil, err
	}

	return true, &saResult{
		data:   []byte(meta),
		values: values,
	}, nil
}

type saResult struct {
	data   []byte
	values helmify.Values
}

func (r *saResult) Filename() string {
	return "serviceaccount.yaml"
}

func (r *saResult) Values() helmify.Values {
	return r.values
}

func (r *saResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
07070100000088000081A400000000000000000000000167C862590000032D000000000000000000000000000000000000003900000000helmify-0.4.18/pkg/processor/rbac/serviceaccount_test.gopackage rbac

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const serviceAccountYaml = `apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-operator-controller-manager
  namespace: my-operator-system`

func Test_serviceAccount_Process(t *testing.T) {
	var testInstance serviceAccount

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(serviceAccountYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000089000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002400000000helmify-0.4.18/pkg/processor/secret0707010000008A000081A400000000000000000000000167C8625900000EC9000000000000000000000000000000000000002E00000000helmify-0.4.18/pkg/processor/secret/secret.gopackage secret

import (
	"fmt"
	"github.com/arttor/helmify/pkg/format"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var secretTempl, _ = template.New("secret").Parse(
	`{{ .Meta }}
{{- if .Data }}
{{ .Data }}
{{- end }}
{{- if .StringData }}
{{ .StringData }}
{{- end }}
{{- if .Type }}
{{ .Type }}
{{- end }}`)

var configMapGVC = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "Secret",
}

// New creates processor for k8s Secret resource.
func New() helmify.Processor {
	return &secret{}
}

type secret struct{}

// Process k8s Secret object into template. Returns false if not capable of processing given resource type.
func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != configMapGVC {
		return false, nil, nil
	}
	sec := corev1.Secret{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &sec)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to secret", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	name := appMeta.TrimName(obj.GetName())
	nameCamelCase := strcase.ToLowerCamel(name)

	secretType := string(sec.Type)
	if secretType != "" {
		secretType, err = yamlformat.Marshal(map[string]interface{}{"type": secretType}, 0)
		if err != nil {
			return true, nil, err
		}
	}

	values := helmify.Values{}
	var data, stringData string
	templatedData := map[string]string{}
	for key := range sec.Data {
		keyCamelCase := strcase.ToLowerCamel(key)
		if key == strings.ToUpper(key) {
			keyCamelCase = strcase.ToLowerCamel(strings.ToLower(key))
		}
		templatedName, err := values.AddSecret(true, nameCamelCase, keyCamelCase)
		if err != nil {
			return true, nil, fmt.Errorf("%w: unable add secret to values", err)
		}
		templatedData[key] = templatedName
	}
	if len(templatedData) != 0 {
		data, err = yamlformat.Marshal(map[string]interface{}{"data": templatedData}, 0)
		if err != nil {
			return true, nil, err
		}
		data = strings.ReplaceAll(data, "'", "")
		data = format.FixUnterminatedQuotes(data)
	}

	templatedData = map[string]string{}
	for key := range sec.StringData {
		keyCamelCase := strcase.ToLowerCamel(key)
		if key == strings.ToUpper(key) {
			keyCamelCase = strcase.ToLowerCamel(strings.ToLower(key))
		}
		templatedName, err := values.AddSecret(false, nameCamelCase, keyCamelCase)
		if err != nil {
			return true, nil, fmt.Errorf("%w: unable add secret to values", err)
		}
		templatedData[key] = templatedName
	}
	if len(templatedData) != 0 {
		stringData, err = yamlformat.Marshal(map[string]interface{}{"stringData": templatedData}, 0)
		if err != nil {
			return true, nil, err
		}
		stringData = strings.ReplaceAll(stringData, "'", "")
		stringData = format.FixUnterminatedQuotes(stringData)
	}

	return true, &result{
		name: name + ".yaml",
		data: struct {
			Type       string
			Meta       string
			Data       string
			StringData string
		}{Type: secretType, Meta: meta, Data: data, StringData: stringData},
		values: values,
	}, nil
}

type result struct {
	name string
	data struct {
		Type       string
		Meta       string
		Data       string
		StringData string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return secretTempl.Execute(writer, r.data)
}
0707010000008B000081A400000000000000000000000167C862590000036F000000000000000000000000000000000000003300000000helmify-0.4.18/pkg/processor/secret/secret_test.gopackage secret

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const secretYaml = `apiVersion: v1
data:
  VAR1: bXlfc2VjcmV0X3Zhcl8x
  VAR2: bXlfc2VjcmV0X3Zhcl8y
stringData:
  VAR3: string secret
kind: Secret
metadata:
  name: my-operator-secret-vars
  namespace: my-operator-system
type: opaque`

func Test_secret_Process(t *testing.T) {
	var testInstance secret

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(secretYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
0707010000008C000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002E00000000helmify-0.4.18/pkg/processor/security-context0707010000008D000081A400000000000000000000000167C8625900000821000000000000000000000000000000000000004C00000000helmify-0.4.18/pkg/processor/security-context/container_security_context.gopackage security_context

import (
	"fmt"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/iancoleman/strcase"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const (
	sc           = "securityContext"
	cscValueName = "containerSecurityContext"
	helmTemplate = "{{- toYaml .Values.%[1]s.%[2]s.containerSecurityContext | nindent 10 }}"
)

// ProcessContainerSecurityContext adds 'securityContext' to the podSpec in specMap, if it doesn't have one already defined.
func ProcessContainerSecurityContext(nameCamel string, specMap map[string]interface{}, values *helmify.Values) error {
	err := processSecurityContext(nameCamel, "containers", specMap, values)
	if err != nil {
		return err
	}

	err = processSecurityContext(nameCamel, "initContainers", specMap, values)
	if err != nil {
		return err
	}

	return nil
}

func processSecurityContext(nameCamel string, containerType string, specMap map[string]interface{}, values *helmify.Values) error {
	if containers, defined := specMap[containerType]; defined {
		for _, container := range containers.([]interface{}) {
			castedContainer := container.(map[string]interface{})
			containerName := strcase.ToLowerCamel(castedContainer["name"].(string))
			if _, defined2 := castedContainer["securityContext"]; defined2 {
				err := setSecContextValue(nameCamel, containerName, castedContainer, values)
				if err != nil {
					return err
				}
			}
		}
		err := unstructured.SetNestedField(specMap, containers, containerType)
		if err != nil {
			return err
		}
	}
	return nil
}

func setSecContextValue(resourceName string, containerName string, castedContainer map[string]interface{}, values *helmify.Values) error {
	if castedContainer["securityContext"] != nil {
		err := unstructured.SetNestedField(*values, castedContainer["securityContext"], resourceName, containerName, cscValueName)
		if err != nil {
			return err
		}

		valueString := fmt.Sprintf(helmTemplate, resourceName, containerName)

		err = unstructured.SetNestedField(castedContainer, valueString, sc)
		if err != nil {
			return err
		}
	}
	return nil
}
0707010000008E000081A400000000000000000000000167C8625900000E27000000000000000000000000000000000000005100000000helmify-0.4.18/pkg/processor/security-context/container_security_context_test.gopackage security_context

import (
	"testing"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/stretchr/testify/assert"
)

func TestProcessContainerSecurityContext(t *testing.T) {
	type args struct {
		nameCamel string
		specMap   map[string]interface{}
		values    *helmify.Values
	}
	tests := []struct {
		name string
		args args
		want *helmify.Values
	}{
		{
			name: "test with empty specMap",
			args: args{
				nameCamel: "someResourceName",
				specMap:   map[string]interface{}{},
				values:    &helmify.Values{},
			},
			want: &helmify.Values{},
		},
		{
			name: "test with single container",
			args: args{
				nameCamel: "someResourceName",
				specMap: map[string]interface{}{
					"containers": []interface{}{
						map[string]interface{}{
							"name": "SomeContainerName",
							"securityContext": map[string]interface{}{
								"privileged": true,
							},
						},
					},
				},
				values: &helmify.Values{},
			},
			want: &helmify.Values{
				"someResourceName": map[string]interface{}{
					"someContainerName": map[string]interface{}{
						"containerSecurityContext": map[string]interface{}{
							"privileged": true,
						},
					},
				},
			},
		},
		{
			name: "test with multiple containers",
			args: args{
				nameCamel: "someResourceName",
				specMap: map[string]interface{}{
					"containers": []interface{}{
						map[string]interface{}{
							"name": "FirstContainer",
							"securityContext": map[string]interface{}{
								"privileged": true,
							},
						},
						map[string]interface{}{
							"name": "SecondContainer",
							"securityContext": map[string]interface{}{
								"allowPrivilegeEscalation": true,
							},
						},
					},
				},
				values: &helmify.Values{},
			},
			want: &helmify.Values{
				"someResourceName": map[string]interface{}{
					"firstContainer": map[string]interface{}{
						"containerSecurityContext": map[string]interface{}{
							"privileged": true,
						},
					},
					"secondContainer": map[string]interface{}{
						"containerSecurityContext": map[string]interface{}{
							"allowPrivilegeEscalation": true,
						},
					},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ProcessContainerSecurityContext(tt.args.nameCamel, tt.args.specMap, tt.args.values)
			assert.Equal(t, tt.want, tt.args.values)
		})
	}
}

func Test_setSecContextValue(t *testing.T) {
	type args struct {
		resourceName            string
		containerName           string
		castedContainer         map[string]interface{}
		values                  *helmify.Values
		fieldName               string
		useRenderedHelmTemplate bool
	}
	tests := []struct {
		name string
		args args
		want *helmify.Values
	}{
		{
			name: "simple test with single container and single value",
			args: args{
				resourceName:  "someResource",
				containerName: "someContainer",
				castedContainer: map[string]interface{}{
					"securityContext": map[string]interface{}{
						"someField": "someValue",
					},
				},
				values:                  &helmify.Values{},
				fieldName:               "someField",
				useRenderedHelmTemplate: false,
			},
			want: &helmify.Values{
				"someResource": map[string]interface{}{
					"someContainer": map[string]interface{}{
						"containerSecurityContext": map[string]interface{}{
							"someField": "someValue",
						},
					},
				},
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			setSecContextValue(tt.args.resourceName, tt.args.containerName, tt.args.castedContainer, tt.args.values)
			assert.Equal(t, tt.want, tt.args.values)
		})
	}
}
0707010000008F000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/processor/service07070100000090000081A400000000000000000000000167C8625900000A3B000000000000000000000000000000000000003000000000helmify-0.4.18/pkg/processor/service/ingress.gopackage service

import (
	"fmt"
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"io"
	networkingv1 "k8s.io/api/networking/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"text/template"
)

var ingressTempl, _ = template.New("ingress").Parse(
	`{{ .Meta }}
{{ .Spec }}`)

var ingressGVC = schema.GroupVersionKind{
	Group:   "networking.k8s.io",
	Version: "v1",
	Kind:    "Ingress",
}

// NewIngress creates processor for k8s Ingress resource.
func NewIngress() helmify.Processor {
	return &ingress{}
}

type ingress struct{}

// Process k8s Service object into template. Returns false if not capable of processing given resource type.
func (r ingress) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != ingressGVC {
		return false, nil, nil
	}
	ing := networkingv1.Ingress{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &ing)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to ingress", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}
	name := appMeta.TrimName(obj.GetName())
	processIngressSpec(appMeta, &ing.Spec)
	spec, err := yamlformat.Marshal(map[string]interface{}{"spec": &ing.Spec}, 0)
	if err != nil {
		return true, nil, err
	}

	return true, &ingressResult{
		name: name + ".yaml",
		data: struct {
			Meta string
			Spec string
		}{Meta: meta, Spec: spec},
	}, nil
}

func processIngressSpec(appMeta helmify.AppMetadata, ing *networkingv1.IngressSpec) {
	if ing.DefaultBackend != nil && ing.DefaultBackend.Service != nil {
		ing.DefaultBackend.Service.Name = appMeta.TemplatedName(ing.DefaultBackend.Service.Name)
	}
	for i := range ing.Rules {
		if ing.Rules[i].IngressRuleValue.HTTP != nil {
			for j := range ing.Rules[i].IngressRuleValue.HTTP.Paths {
				if ing.Rules[i].IngressRuleValue.HTTP.Paths[j].Backend.Service != nil {
					ing.Rules[i].IngressRuleValue.HTTP.Paths[j].Backend.Service.Name = appMeta.TemplatedName(ing.Rules[i].IngressRuleValue.HTTP.Paths[j].Backend.Service.Name)
				}
			}
		}
	}
}

type ingressResult struct {
	name string
	data struct {
		Meta string
		Spec string
	}
}

func (r *ingressResult) Filename() string {
	return r.name
}

func (r *ingressResult) Values() helmify.Values {
	return helmify.Values{}
}

func (r *ingressResult) Write(writer io.Writer) error {
	return ingressTempl.Execute(writer, r.data)
}
07070100000091000081A400000000000000000000000167C8625900000417000000000000000000000000000000000000003500000000helmify-0.4.18/pkg/processor/service/ingress_test.gopackage service

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const ingressYaml = `apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /testpath
            pathType: Prefix
            backend:
              service:
                name: myapp-service
                port:
                  number: 8443`

func Test_ingress_Process(t *testing.T) {
	var testInstance ingress

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(ingressYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000092000081A400000000000000000000000167C8625900000F45000000000000000000000000000000000000003000000000helmify-0.4.18/pkg/processor/service/service.gopackage service

import (
	"bytes"
	"fmt"
	"io"
	"strings"

	"github.com/arttor/helmify/pkg/processor"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/intstr"
	"sigs.k8s.io/yaml"
)

const (
	svcTempSpec = `
spec:
  type: {{ .Values.%[1]s.type }}
  selector:
%[2]s
    {{- include "%[3]s.selectorLabels" . | nindent 4 }}
  ports:
  {{- .Values.%[1]s.ports | toYaml | nindent 2 }}`
)

const (
	lbSourceRangesTempSpec = `
  loadBalancerSourceRanges:
  {{- .Values.%[1]s.loadBalancerSourceRanges | toYaml | nindent 2 }}`
)

var svcGVC = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "Service",
}

// New creates processor for k8s Service resource.
func New() helmify.Processor {
	return &svc{}
}

type svc struct{}

// Process k8s Service object into template. Returns false if not capable of processing given resource type.
func (r svc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != svcGVC {
		return false, nil, nil
	}
	service := corev1.Service{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &service)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to service", err)
	}

	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	name := appMeta.TrimName(obj.GetName())
	shortName := strings.TrimPrefix(name, "controller-manager-")
	shortNameCamel := strcase.ToLowerCamel(shortName)

	selector, _ := yaml.Marshal(service.Spec.Selector)
	selector = yamlformat.Indent(selector, 4)
	selector = bytes.TrimRight(selector, "\n ")

	values := helmify.Values{}
	svcType := service.Spec.Type
	if svcType == "" {
		svcType = corev1.ServiceTypeClusterIP
	}
	_ = unstructured.SetNestedField(values, string(svcType), shortNameCamel, "type")
	ports := make([]interface{}, len(service.Spec.Ports))
	for i, p := range service.Spec.Ports {
		pMap := map[string]interface{}{
			"port": int64(p.Port),
		}
		if p.Name != "" {
			pMap["name"] = p.Name
		}
		if p.NodePort != 0 {
			pMap["nodePort"] = int64(p.NodePort)
		}
		if p.Protocol != "" {
			pMap["protocol"] = string(p.Protocol)
		}
		if p.TargetPort.Type == intstr.Int {
			pMap["targetPort"] = int64(p.TargetPort.IntVal)
		} else {
			pMap["targetPort"] = p.TargetPort.StrVal
		}
		ports[i] = pMap
	}

	_ = unstructured.SetNestedSlice(values, ports, shortNameCamel, "ports")
	res := meta + fmt.Sprintf(svcTempSpec, shortNameCamel, selector, appMeta.ChartName())

	res += parseLoadBalancerSourceRanges(values, service, shortNameCamel)

	if shortNameCamel == "webhookService" && appMeta.Config().AddWebhookOption {
		res = fmt.Sprintf("{{- if .Values.webhook.enabled }}\n%s\n{{- end }}", res)
	}
	return true, &result{
		name:   shortName,
		data:   res,
		values: values,
	}, nil
}

func parseLoadBalancerSourceRanges(values helmify.Values, service corev1.Service, shortNameCamel string) string {
	if len(service.Spec.LoadBalancerSourceRanges) < 1 {
		return ""
	}
	lbSourceRanges := make([]interface{}, len(service.Spec.LoadBalancerSourceRanges))
	for i, ip := range service.Spec.LoadBalancerSourceRanges {
		lbSourceRanges[i] = ip
	}
	_ = unstructured.SetNestedSlice(values, lbSourceRanges, shortNameCamel, "loadBalancerSourceRanges")
	return fmt.Sprintf(lbSourceRangesTempSpec, shortNameCamel)
}

type result struct {
	name   string
	data   string
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name + ".yaml"
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	_, err := writer.Write([]byte(r.data))
	return err
}
07070100000093000081A400000000000000000000000167C86259000003B3000000000000000000000000000000000000003500000000helmify-0.4.18/pkg/processor/service/service_test.gopackage service

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const svcYaml = `apiVersion: v1
kind: Service
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager-metrics-service
  namespace: my-operator-system
spec:
  ports:
  - name: https
    port: 8443
    targetPort: https
  selector:
    control-plane: controller-manager`

func Test_svc_Process(t *testing.T) {
	var testInstance svc

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(svcYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000094000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002900000000helmify-0.4.18/pkg/processor/statefulset07070100000095000081A400000000000000000000000167C86259000010CE000000000000000000000000000000000000003800000000helmify-0.4.18/pkg/processor/statefulset/statefulset.gopackage statefulset

import (
	"fmt"
	"github.com/arttor/helmify/pkg/processor/pod"
	"io"
	"strings"
	"text/template"

	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	appsv1 "k8s.io/api/apps/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

var statefulsetGVC = schema.GroupVersionKind{
	Group:   "apps",
	Version: "v1",
	Kind:    "StatefulSet",
}

var statefulsetTempl, _ = template.New("statefulset").Parse(
	`{{- .Meta }}
spec:
{{ .Spec }}`)

// New creates processor for k8s StatefulSet resource.
func New() helmify.Processor {
	return &statefulset{}
}

type statefulset struct{}

// Process k8s StatefulSet object into template. Returns false if not capable of processing given resource type.
func (d statefulset) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != statefulsetGVC {
		return false, nil, nil
	}
	ss := appsv1.StatefulSet{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &ss)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to StatefulSet", err)
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	ssSpec := ss.Spec
	ssSpecMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&ssSpec)
	if err != nil {
		return true, nil, err
	}
	delete((ssSpecMap["template"].(map[string]interface{}))["metadata"].(map[string]interface{}), "creationTimestamp")

	values := helmify.Values{}

	name := appMeta.TrimName(obj.GetName())
	nameCamel := strcase.ToLowerCamel(name)

	if ssSpec.ServiceName != "" {
		servName := appMeta.TemplatedName(ssSpec.ServiceName)
		ssSpecMap["serviceName"] = servName
	}

	if ssSpec.Replicas != nil {
		repl, err := values.Add(*ssSpec.Replicas, nameCamel, "replicas")
		if err != nil {
			return true, nil, err
		}
		ssSpecMap["replicas"] = repl
	}

	for i, claim := range ssSpec.VolumeClaimTemplates {
		volName := claim.ObjectMeta.Name
		delete(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), "status")
		if claim.Spec.StorageClassName != nil {
			scName := appMeta.TemplatedName(*claim.Spec.StorageClassName)
			err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), scName, "spec", "storageClassName")
			if err != nil {
				return true, nil, err
			}
		}
		if claim.Spec.VolumeName != "" {
			vName := appMeta.TemplatedName(claim.Spec.VolumeName)
			err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), vName, "spec", "volumeName")
			if err != nil {
				return true, nil, err
			}
		}

		resMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&claim.Spec.Resources)
		if err != nil {
			return true, nil, err
		}
		resName, err := values.AddYaml(resMap, 8, true, nameCamel, "volumeClaims", volName)
		if err != nil {
			return true, nil, err
		}
		err = unstructured.SetNestedField(((ssSpecMap["volumeClaimTemplates"].([]interface{}))[i]).(map[string]interface{}), resName, "spec", "resources")
		if err != nil {
			return true, nil, err
		}
	}

	// process pod spec:
	podSpecMap, podValues, err := pod.ProcessSpec(nameCamel, appMeta, ssSpec.Template.Spec)
	if err != nil {
		return true, nil, err
	}
	err = values.Merge(podValues)
	if err != nil {
		return true, nil, err
	}
	err = unstructured.SetNestedMap(ssSpecMap, podSpecMap, "template", "spec")
	if err != nil {
		return true, nil, err
	}

	spec, err := yamlformat.Marshal(ssSpecMap, 2)
	if err != nil {
		return true, nil, err
	}
	spec = strings.ReplaceAll(spec, "'", "")

	return true, &result{
		values: values,
		data: struct {
			Meta string
			Spec string
		}{
			Meta: meta,
			Spec: spec,
		},
	}, nil
}

type result struct {
	data struct {
		Meta string
		Spec string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return "statefulset.yaml"
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return statefulsetTempl.Execute(writer, r.data)
}
07070100000096000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/processor/storage07070100000097000081A400000000000000000000000167C8625900000CA3000000000000000000000000000000000000002C00000000helmify-0.4.18/pkg/processor/storage/pvc.gopackage storage

import (
	"fmt"
	"github.com/arttor/helmify/pkg/helmify"
	"github.com/arttor/helmify/pkg/processor"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"github.com/iancoleman/strcase"
	"io"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"strings"
	"text/template"
)

var pvcTempl, _ = template.New("pvc").Parse(
	`{{ .Meta }}
{{ .Spec }}`)

var pvcGVC = schema.GroupVersionKind{
	Group:   "",
	Version: "v1",
	Kind:    "PersistentVolumeClaim",
}

// New creates processor for k8s PVC resource.
func New() helmify.Processor {
	return &pvc{}
}

type pvc struct{}

// Process k8s PVC object into template. Returns false if not capable of processing given resource type.
func (p pvc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != pvcGVC {
		return false, nil, nil
	}
	meta, err := processor.ProcessObjMeta(appMeta, obj)
	if err != nil {
		return true, nil, err
	}

	name := appMeta.TrimName(obj.GetName())
	nameCamelCase := strcase.ToLowerCamel(name)
	values := helmify.Values{}

	claim := corev1.PersistentVolumeClaim{}
	err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &claim)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to PVC", err)
	}

	// template storage class name
	if claim.Spec.StorageClassName != nil {
		templatedSC, err := values.Add(*claim.Spec.StorageClassName, "pvc", nameCamelCase, "storageClass")
		if err != nil {
			return true, nil, err
		}
		claim.Spec.StorageClassName = &templatedSC
	}

	// template resources
	specMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&claim.Spec)
	if err != nil {
		return true, nil, err
	}

	storageReq, ok, _ := unstructured.NestedString(specMap, "resources", "requests", "storage")
	if ok {
		templatedStorageReq, err := values.Add(storageReq, "pvc", nameCamelCase, "storageRequest")
		if err != nil {
			return true, nil, err
		}
		err = unstructured.SetNestedField(specMap, templatedStorageReq, "resources", "requests", "storage")
		if err != nil {
			return true, nil, err
		}
	}

	storageLim, ok, _ := unstructured.NestedString(specMap, "resources", "limits", "storage")
	if ok {
		templatedStorageLim, err := values.Add(storageLim, "pvc", nameCamelCase, "storageLimit")
		if err != nil {
			return true, nil, err
		}
		err = unstructured.SetNestedField(specMap, templatedStorageLim, "resources", "limits", "storage")
		if err != nil {
			return true, nil, err
		}
	}

	spec, err := yamlformat.Marshal(map[string]interface{}{"spec": specMap}, 0)
	if err != nil {
		return true, nil, err
	}
	spec = strings.ReplaceAll(spec, "'", "")

	return true, &result{
		name: name + ".yaml",
		data: struct {
			Meta string
			Spec string
		}{Meta: meta, Spec: spec},
		values: values,
	}, nil
}

type result struct {
	name string
	data struct {
		Meta string
		Spec string
	}
	values helmify.Values
}

func (r *result) Filename() string {
	return r.name
}

func (r *result) Values() helmify.Values {
	return r.values
}

func (r *result) Write(writer io.Writer) error {
	return pvcTempl.Execute(writer, r.data)
}
07070100000098000081A400000000000000000000000167C862590000036B000000000000000000000000000000000000003100000000helmify-0.4.18/pkg/processor/storage/pvc_test.gopackage storage

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const pvcYaml = `apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
    limits:
      storage: 5Gi`

func Test_PVC_Process(t *testing.T) {
	var testInstance pvc

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(pvcYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
07070100000099000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/processor/webhook0707010000009A000081A400000000000000000000000167C8625900000E0D000000000000000000000000000000000000002D00000000helmify-0.4.18/pkg/processor/webhook/cert.gopackage webhook

import (
	"bytes"
	"fmt"
	"io"
	"strings"

	"github.com/arttor/helmify/pkg/cluster"
	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"
)

const (
	WebhookHeader = `{{- if .Values.webhook.enabled }}`
	WebhookFooter = `{{- end }}`
	certTempl     = `apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
spec:
%[3]s`
	certTemplWithAnno = `apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-weight": "2"
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
spec:
%[3]s`
)

var certGVC = schema.GroupVersionKind{
	Group:   "cert-manager.io",
	Version: "v1",
	Kind:    "Certificate",
}

// Certificate creates processor for k8s Certificate resource.
func Certificate() helmify.Processor {
	return &cert{}
}

type cert struct{}

// Process k8s Certificate object into template. Returns false if not capable of processing given resource type.
func (c cert) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != certGVC {
		return false, nil, nil
	}
	name := appMeta.TrimName(obj.GetName())

	dnsNames, _, err := unstructured.NestedSlice(obj.Object, "spec", "dnsNames")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable get cert dnsNames", err)
	}

	processedDnsNames := []interface{}{}
	for _, dnsName := range dnsNames {
		dns := dnsName.(string)
		templatedDns := appMeta.TemplatedString(dns)
		processedDns := strings.ReplaceAll(templatedDns, appMeta.Namespace(), "{{ .Release.Namespace }}")
		processedDns = strings.ReplaceAll(processedDns, cluster.DefaultDomain, fmt.Sprintf("{{ .Values.%s }}", cluster.DomainKey))
		processedDnsNames = append(processedDnsNames, processedDns)
	}
	err = unstructured.SetNestedSlice(obj.Object, processedDnsNames, "spec", "dnsNames")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable set cert dnsNames", err)
	}

	issName, _, err := unstructured.NestedString(obj.Object, "spec", "issuerRef", "name")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable get cert issuerRef", err)
	}
	issName = appMeta.TemplatedName(issName)
	err = unstructured.SetNestedField(obj.Object, issName, "spec", "issuerRef", "name")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable set cert issuerRef", err)
	}
	spec, _ := yaml.Marshal(obj.Object["spec"])
	spec = yamlformat.Indent(spec, 2)
	spec = bytes.TrimRight(spec, "\n ")
	tmpl := ""
	if appMeta.Config().CertManagerAsSubchart {
		tmpl = certTemplWithAnno
	} else {
		tmpl = certTempl
	}
	values := helmify.Values{}
	if appMeta.Config().AddWebhookOption {
		// Add webhook.enabled value to values.yaml
		_, _ = values.Add(true, "webhook", "enabled")

		tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, tmpl, WebhookFooter)
	}
	res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, string(spec))
	return true, &certResult{
		name:   name,
		data:   []byte(res),
		values: values,
	}, nil
}

type certResult struct {
	name   string
	data   []byte
	values helmify.Values
}

func (r *certResult) Filename() string {
	return r.name + ".yaml"
}

func (r *certResult) Values() helmify.Values {
	return r.values
}

func (r *certResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
0707010000009B000081A400000000000000000000000167C8625900000405000000000000000000000000000000000000003200000000helmify-0.4.18/pkg/processor/webhook/cert_test.gopackage webhook

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const certYaml = `apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-operator-serving-cert
  namespace: my-operator-system
spec:
  dnsNames:
  - my-operator-webhook-service.my-operator-system.svc
  - my-operator-webhook-service.my-operator-system.svc.cluster.local
  issuerRef:
    kind: Issuer
    name: my-operator-selfsigned-issuer
  secretName: webhook-server-cert`

func Test_cert_Process(t *testing.T) {
	var testInstance cert

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(certYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
0707010000009C000081A400000000000000000000000167C86259000008C3000000000000000000000000000000000000002F00000000helmify-0.4.18/pkg/processor/webhook/issuer.gopackage webhook

import (
	"bytes"
	"fmt"
	"io"

	"github.com/arttor/helmify/pkg/helmify"
	yamlformat "github.com/arttor/helmify/pkg/yaml"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"
)

const (
	issuerTempl = `apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
spec:
%[3]s`
	issuerTemplWithAnno = `apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-weight": "1"
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
spec:
%[3]s`
)

var issuerGVC = schema.GroupVersionKind{
	Group:   "cert-manager.io",
	Version: "v1",
	Kind:    "Issuer",
}

// Issuer creates processor for k8s Issuer resource.
func Issuer() helmify.Processor {
	return &issuer{}
}

type issuer struct{}

// Process k8s Issuer object into template. Returns false if not capable of processing given resource type.
func (i issuer) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != issuerGVC {
		return false, nil, nil
	}
	name := appMeta.TrimName(obj.GetName())

	spec, _ := yaml.Marshal(obj.Object["spec"])
	spec = yamlformat.Indent(spec, 2)
	spec = bytes.TrimRight(spec, "\n ")
	tmpl := ""
	if appMeta.Config().CertManagerAsSubchart {
		tmpl = issuerTemplWithAnno
	} else {
		tmpl = issuerTempl
	}
	values := helmify.Values{}
	if appMeta.Config().AddWebhookOption {
		// Add webhook.enabled value to values.yaml
		_, _ = values.Add(true, "webhook", "enabled")

		tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, tmpl, WebhookFooter)
	}
	res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, string(spec))
	return true, &issResult{
		name: name,
		data: []byte(res),
	}, nil
}

type issResult struct {
	name   string
	data   []byte
	values helmify.Values
}

func (r *issResult) Filename() string {
	return r.name + ".yaml"
}

func (r *issResult) Values() helmify.Values {
	return r.values
}

func (r *issResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
0707010000009D000081A400000000000000000000000167C862590000032E000000000000000000000000000000000000003400000000helmify-0.4.18/pkg/processor/webhook/issuer_test.gopackage webhook

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const issuerYaml = `apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: my-operator-selfsigned-issuer
  namespace: my-operator-system
spec:
  selfSigned: {}`

func Test_issuer_Process(t *testing.T) {
	var testInstance issuer

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(issuerYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
0707010000009E000081A400000000000000000000000167C8625900000B9C000000000000000000000000000000000000003100000000helmify-0.4.18/pkg/processor/webhook/mutating.gopackage webhook

import (
	"bytes"
	"fmt"
	"io"
	"strings"

	"github.com/arttor/helmify/pkg/helmify"
	v1 "k8s.io/api/admissionregistration/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"
)

const (
	mwhTempl = `apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  annotations:
    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "%[1]s.fullname" . }}-%[3]s
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
webhooks:
%[4]s`
)

var mwhGVK = schema.GroupVersionKind{
	Group:   "admissionregistration.k8s.io",
	Version: "v1",
	Kind:    "MutatingWebhookConfiguration",
}

// MutatingWebhook creates processor for k8s MutatingWebhookConfiguration resource.
func MutatingWebhook() helmify.Processor {
	return &mwh{}
}

type mwh struct{}

// Process k8s MutatingWebhookConfiguration object into template. Returns false if not capable of processing given resource type.
func (w mwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != mwhGVK {
		return false, nil, nil
	}
	name := appMeta.TrimName(obj.GetName())

	whConf := v1.MutatingWebhookConfiguration{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &whConf)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to MutatingWebhookConfiguration", err)
	}
	for i, whc := range whConf.Webhooks {
		whc.ClientConfig.Service.Name = appMeta.TemplatedName(whc.ClientConfig.Service.Name)
		whc.ClientConfig.Service.Namespace = strings.ReplaceAll(whc.ClientConfig.Service.Namespace, appMeta.Namespace(), `{{ .Release.Namespace }}`)
		whConf.Webhooks[i] = whc
	}
	webhooks, _ := yaml.Marshal(whConf.Webhooks)
	webhooks = bytes.TrimRight(webhooks, "\n ")
	certName, _, err := unstructured.NestedString(obj.Object, "metadata", "annotations", "cert-manager.io/inject-ca-from")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable get webhook certName", err)
	}
	certName = strings.TrimPrefix(certName, appMeta.Namespace()+"/")
	certName = appMeta.TrimName(certName)
	tmpl := mwhTempl
	values := helmify.Values{}
	if appMeta.Config().AddWebhookOption {
		// Add webhook.enabled value to values.yaml
		_, _ = values.Add(true, "webhook", "enabled")

		tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, mwhTempl, WebhookFooter)
	}
	res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, certName, string(webhooks))
	return true, &mwhResult{
		name: name,
		data: []byte(res),
	}, nil
}

type mwhResult struct {
	name   string
	data   []byte
	values helmify.Values
}

func (r *mwhResult) Filename() string {
	return r.name + ".yaml"
}

func (r *mwhResult) Values() helmify.Values {
	return r.values
}

func (r *mwhResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
0707010000009F000081A400000000000000000000000167C8625900000526000000000000000000000000000000000000003600000000helmify-0.4.18/pkg/processor/webhook/mutating_test.gopackage webhook

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const mwhYaml = `apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  name: my-operator-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: my-operator-webhook-service
      namespace: my-operator-system
      path: /mutate-ceph-example-com-v1alpha1-volume
  failurePolicy: Fail
  name: vvolume.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1alpha1
    operations:
    - CREATE
    - UPDATE
    resources:
    - volumes
  sideEffects: None`

func Test_mwh_Process(t *testing.T) {
	var testInstance mwh

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(mwhYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
070701000000A0000081A400000000000000000000000167C8625900000BAC000000000000000000000000000000000000003300000000helmify-0.4.18/pkg/processor/webhook/validating.gopackage webhook

import (
	"bytes"
	"fmt"
	"io"
	"strings"

	"github.com/arttor/helmify/pkg/helmify"
	v1 "k8s.io/api/admissionregistration/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/yaml"
)

const (
	vwhTempl = `apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: {{ include "%[1]s.fullname" . }}-%[2]s
  annotations:
    cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "%[1]s.fullname" . }}-%[3]s
  labels:
  {{- include "%[1]s.labels" . | nindent 4 }}
webhooks:
%[4]s`
)

var vwhGVK = schema.GroupVersionKind{
	Group:   "admissionregistration.k8s.io",
	Version: "v1",
	Kind:    "ValidatingWebhookConfiguration",
}

// ValidatingWebhook creates processor for k8s ValidatingWebhookConfiguration resource.
func ValidatingWebhook() helmify.Processor {
	return &vwh{}
}

type vwh struct{}

// Process k8s ValidatingWebhookConfiguration object into template. Returns false if not capable of processing given resource type.
func (w vwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured) (bool, helmify.Template, error) {
	if obj.GroupVersionKind() != vwhGVK {
		return false, nil, nil
	}
	name := appMeta.TrimName(obj.GetName())

	whConf := v1.ValidatingWebhookConfiguration{}
	err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &whConf)
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable to cast to ValidatingWebhookConfiguration", err)
	}
	for i, whc := range whConf.Webhooks {
		whc.ClientConfig.Service.Name = appMeta.TemplatedName(whc.ClientConfig.Service.Name)
		whc.ClientConfig.Service.Namespace = strings.ReplaceAll(whc.ClientConfig.Service.Namespace, appMeta.Namespace(), `{{ .Release.Namespace }}`)
		whConf.Webhooks[i] = whc
	}
	webhooks, _ := yaml.Marshal(whConf.Webhooks)
	webhooks = bytes.TrimRight(webhooks, "\n ")
	certName, _, err := unstructured.NestedString(obj.Object, "metadata", "annotations", "cert-manager.io/inject-ca-from")
	if err != nil {
		return true, nil, fmt.Errorf("%w: unable get webhook certName", err)
	}
	certName = strings.TrimPrefix(certName, appMeta.Namespace()+"/")
	certName = appMeta.TrimName(certName)
	tmpl := vwhTempl
	values := helmify.Values{}
	if appMeta.Config().AddWebhookOption {
		// Add webhook.enabled value to values.yaml
		_, _ = values.Add(true, "webhook", "enabled")

		tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, mwhTempl, WebhookFooter)
	}
	res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, certName, string(webhooks))
	return true, &vwhResult{
		name: name,
		data: []byte(res),
	}, nil
}

type vwhResult struct {
	name   string
	data   []byte
	values helmify.Values
}

func (r *vwhResult) Filename() string {
	return r.name + ".yaml"
}

func (r *vwhResult) Values() helmify.Values {
	return r.values
}

func (r *vwhResult) Write(writer io.Writer) error {
	_, err := writer.Write(r.data)
	return err
}
070701000000A1000081A400000000000000000000000167C862590000052C000000000000000000000000000000000000003800000000helmify-0.4.18/pkg/processor/webhook/validating_test.gopackage webhook

import (
	"testing"

	"github.com/arttor/helmify/pkg/metadata"

	"github.com/arttor/helmify/internal"
	"github.com/stretchr/testify/assert"
)

const vwhYaml = `apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  name: my-operator-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: my-operator-webhook-service
      namespace: my-operator-system
      path: /validate-ceph-example-com-v1alpha1-volume
  failurePolicy: Fail
  name: vvolume.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1alpha1
    operations:
    - CREATE
    - UPDATE
    resources:
    - volumes
  sideEffects: None`

func Test_vwh_Process(t *testing.T) {
	var testInstance vwh

	t.Run("processed", func(t *testing.T) {
		obj := internal.GenerateObj(vwhYaml)
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, true, processed)
	})
	t.Run("skipped", func(t *testing.T) {
		obj := internal.TestNs
		processed, _, err := testInstance.Process(&metadata.Service{}, obj)
		assert.NoError(t, err)
		assert.Equal(t, false, processed)
	})
}
070701000000A2000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001800000000helmify-0.4.18/pkg/yaml070701000000A3000081A400000000000000000000000167C862590000029B000000000000000000000000000000000000002000000000helmify-0.4.18/pkg/yaml/yaml.gopackage yaml

import (
	"bytes"

	"sigs.k8s.io/yaml"
)

// Indent - adds indentation to given content.
func Indent(content []byte, n int) []byte {
	if n < 0 {
		return content
	}
	prefix := append([]byte("\n"), bytes.Repeat([]byte(" "), n)...)
	content = append(prefix[1:], content...)
	return bytes.ReplaceAll(content, []byte("\n"), prefix)
}

// Marshal object to yaml string with indentation.
func Marshal(object interface{}, indent int) (string, error) {
	objectBytes, err := yaml.Marshal(object)
	if err != nil {
		return "", err
	}
	objectBytes = Indent(objectBytes, indent)
	objectBytes = bytes.TrimRight(objectBytes, "\n ")
	return string(objectBytes), nil
}
070701000000A4000081A400000000000000000000000167C86259000002E6000000000000000000000000000000000000002500000000helmify-0.4.18/pkg/yaml/yaml_test.gopackage yaml

import (
	"reflect"
	"testing"
)

func TestIndent(t *testing.T) {
	type args struct {
		content []byte
		n       int
	}
	tests := []struct {
		name string
		args args
		want []byte
	}{
		{
			name: "negative",
			args: args{[]byte("a"), -1},
			want: []byte("a"),
		},
		{
			name: "none",
			args: args{[]byte("a"), 0},
			want: []byte("a"),
		},
		{
			name: "one",
			args: args{[]byte("a"), 1},
			want: []byte(" a"),
		},
		{
			name: "two",
			args: args{[]byte("a"), 2},
			want: []byte("  a"),
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := Indent(tt.args.content, tt.args.n); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("Indent() = %v, want %v", got, tt.want)
			}
		})
	}
}
070701000000A5000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001900000000helmify-0.4.18/test_data070701000000A6000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000001D00000000helmify-0.4.18/test_data/dir070701000000A7000041ED00000000000000000000000267C8625900000000000000000000000000000000000000000000002900000000helmify-0.4.18/test_data/dir/another_dir070701000000A8000081A400000000000000000000000167C8625900000288000000000000000000000000000000000000003B00000000helmify-0.4.18/test_data/dir/another_dir/stateful_set.yamlapiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: registry.k8s.io/nginx-slim:0.8
          ports:
            - containerPort: 80
              name: web
          volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: www
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 1Gi070701000000A9000081A400000000000000000000000167C86259000002B2000000000000000000000000000000000000002900000000helmify-0.4.18/test_data/dir/config.yamlapiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
  namespace: my-ns
immutable: true
data:
  dummyconfigmapkey: dummyconfigmapvalue
  my_config.properties: |
    health.healthProbeBindAddress=8081
    metrics.bindAddress=127.0.0.1:8080
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config-props
  namespace: my-ns
data:
  my.prop1: "1"
  my.prop2: "val 1"
  my.prop3: "true"
  myval.yaml: |
    apiVersion: clickhouse.altinity.com/v1
    kind: ClickHouseInstallationTemplate
    metadata:
      name: default-oneperhost-pod-template
    spec:
      templates:
        podTemplates: 
          - name: default-oneperhost-pod-template
            distribution: "OnePerHost"070701000000AA000081A400000000000000000000000167C86259000009D3000000000000000000000000000000000000002D00000000helmify-0.4.18/test_data/dir/deployment.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
  namespace: my-ns
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: app
          args:
            - --health-probe-bind-address=:8081
            - --metrics-bind-address=127.0.0.1:8080
            - --leader-elect
          command:
            - /manager
          volumeMounts:
            - mountPath: /my_config.properties
              name: manager-config
              subPath: my_config.properties
            - name: secret-volume
              mountPath: /my.ca
            - name: props
              mountPath: /etc/props
            - name: sample-pv-storage
              mountPath: "/usr/share/nginx/html"
          env:
            - name: VAR1
              valueFrom:
                secretKeyRef:
                  name: my-secret-vars
                  key: VAR1
            - name: VAR2
              valueFrom:
                secretKeyRef:
                  name: my-secret-vars
                  key: VAR2
          image: controller:latest
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8081
            initialDelaySeconds: 15
            periodSeconds: 20
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8081
            initialDelaySeconds: 5
            periodSeconds: 10
          resources:
            limits:
              cpu: 100m
              memory: 30Mi
            requests:
              cpu: 100m
              memory: 20Mi
          securityContext:
            allowPrivilegeEscalation: false
        - name: proxy-sidecar
          args:
            - --secure-listen-address=0.0.0.0:8443
            - --v=10
          image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
          ports:
            - containerPort: 8443
              name: https
      securityContext:
        runAsNonRoot: true
      nodeSelector:
        region: east
        type: user-node
      terminationGracePeriodSeconds: 10
      volumes:
        - configMap:
            name: my-config
          name: manager-config
        - configMap:
            name: my-config-props
          name: props
        - name: secret-volume
          secret:
            secretName: my-secret-ca
        - name: sample-pv-storage
          persistentVolumeClaim:
            claimName: my-sample-pv-claim070701000000AB000081A400000000000000000000000167C8625900000370000000000000000000000000000000000000002900000000helmify-0.4.18/test_data/dir/secret.yamlapiVersion: v1
kind: Secret
metadata:
  name: my-secret-ca
  namespace: my-ns
type: opaque
data:
  ca.crt: |
    c3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3
    VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3Vw
    ZXJsb25ndGVzdGNydC0Kc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cG
    VybG9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVy
    bG9uZ3Rlc3RjcnQKc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG
    9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9u
    Z3Rlc3RjcnQ=
---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret-vars
  namespace: my-ns
type: opaque
data:
  VAR1: bXlfc2VjcmV0X3Zhcl8x
  VAR2: bXlfc2VjcmV0X3Zhcl8y
  ELASTIC_FOOBAR_HUNTER123_MEOWTOWN_VERIFY: bXlfc2VjcmV0X3Zhcl8y
stringData:
  str: |
    some big not so secret string with
    multiple lines070701000000AC000081A400000000000000000000000167C8625900000249000000000000000000000000000000000000002A00000000helmify-0.4.18/test_data/dir/service.yamlapiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myapp-service
  namespace: my-ns
spec:
  ports:
    - name: https
      port: 8443
      targetPort: https
  selector:
    app: myapp
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /testpath
            pathType: Prefix
            backend:
              service:
                name: myapp-service
                port:
                  number: 8443070701000000AD000081A400000000000000000000000167C86259000000E0000000000000000000000000000000000000002A00000000helmify-0.4.18/test_data/dir/storage.yamlapiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-sample-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
    limits:
      storage: 5Gi070701000000AE000081A400000000000000000000000167C86259000052E8000000000000000000000000000000000000002E00000000helmify-0.4.18/test_data/k8s-operator-ci.yamlapiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-system
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
    example-annotation: xyz
  creationTimestamp: null
  name: cephvolumes.test.example.com
  labels:
    example-label: my-app
spec:
  group: test.example.com
  names:
    kind: CephVolume
    listKind: CephVolumeList
    plural: cephvolumes
    singular: cephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.pool
      name: Pool
      type: string
    - description: Storage type
      jsonPath: .status.type
      name: Type
      type: string
    - description: Volume size
      jsonPath: .spec.size
      name: Size
      type: string
    - description: Max number of volume I/O operations per second
      jsonPath: .status.limits.iops
      name: IOPS
      type: string
    - description: true if volume contains latest type,size spec from Ceph
      jsonPath: .status.conditions[?(@.type=="Provided")].status
      name: Provided
      type: string
    - description: true if volume IOPS limits calculated. False indicates error -
        check reason for details
      jsonPath: .status.conditions[?(@.type=="Calculated")].status
      name: Calculated
      type: string
    - description: true if volume IOPS limits applied to volume. False indicates error
        - check reason for details
      jsonPath: .status.conditions[?(@.type=="Limited")].status
      name: Limited
      type: string
    - description: latest resource generation
      jsonPath: .metadata.generation
      name: gen
      type: string
    - description: latest observed generation of Limited condition
      jsonPath: .status.conditions[?(@.type=="Limited")].observedGeneration
      name: Lim-gen
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: CephVolume represents Ceph RBD volume
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: CephVolumeSpec defines the desired state of CephVolume
            properties:
              pool:
                description: Pool - volume pool name
                type: string
              size:
                anyOf:
                - type: integer
                - type: string
                description: Size - volume size
                pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                x-kubernetes-int-or-string: true
            type: object
          status:
            description: CephVolumeStatus defines the observed state of CephVolume
            properties:
              conditions:
                description: 'Conditions represent the latest available observations
                  of an object''s state Known .status.conditions.type are: "Provided".
                  "Calculated", "Limited"'
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    type FooStatus struct{     // Represents the observations of a
                    foo's current state.     // Known .status.conditions.type are:
                    \"Available\", \"Progressing\", and \"Degraded\"     // +patchMergeKey=type
                    \    // +patchStrategy=merge     // +listType=map     // +listMapKey=type
                    \    Conditions []metav1.Condition `json:\"conditions,omitempty\"
                    patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                    \n     // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
              limits:
                description: Limits represent calculated IOPS limits
                properties:
                  iops:
                    description: IOPS - desired limit of IO operations per second.
                      See Ceph rbd_qos_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  iopsBurst:
                    description: IOPSBurst - desired burst limit of IO operations.
                      See Ceph rbd_qos_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPS:
                    description: ReadIOPS - desired limit of read operations per second.
                      See Ceph rbd_qos_read_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPSBurst:
                    description: ReadIOPSBurst - desired burst limit of read operations.
                      See Ceph rbd_qos_read_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPS:
                    description: WriteIOPS - desired limit of write operations per
                      second. See Ceph rbd_qos_write_iops_limit property
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPSBurst:
                    description: WriteIOPSBurst - desired burst limit of write operations.
                      See Ceph rbd_qos_write_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                type: object
              type:
                description: Type - volume storage type. See StorageType CRD.
                type: string
            required:
            - conditions
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  creationTimestamp: null
  name: manifestcephvolumes.test.example.com
spec:
  group: test.example.com
  names:
    kind: ManifestCephVolume
    listKind: ManifestCephVolumeList
    plural: manifestcephvolumes
    singular: manifestcephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.poolName
      name: PoolName
      type: string
    - description: Sync interval in seconds
      jsonPath: .spec.interval
      name: Interval
      type: string
    - description: Last update time
      jsonPath: .status.lastUpdate
      name: LastUpdate
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: ManifestCephVolume monitors given ceph pool and manifests containing
          volumes as CephVolume CR
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: ManifestCephVolumeSpec defines the desired state of ManifestCephVolume
            properties:
              interval:
                description: Interval - Ceph pool polling interval
                format: int32
                minimum: 60
                type: integer
              poolName:
                description: PoolName name of Ceph RBD pool to get volumes
                type: string
            required:
            - interval
            type: object
          status:
            description: ManifestCephVolumeStatus defines the observed state of ManifestCephVolume
            properties:
              lastUpdate:
                description: LastUpdate - time of last successful volumes update
                format: date-time
                type: string
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-operator-controller-manager
  namespace: my-operator-system
  annotations:
    k8s.acme.org/some-meta-data: "ACME Inc."
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-operator-leader-election-role
  namespace: my-operator-system
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: my-operator-manager-aggregated-role
aggregationRule:
  clusterRoleSelectors:
  - matchExpressions:
    - key: app.kubernetes.io/instance
      operator: In
      values:
      - my-operator
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: my-operator-manager-role
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
- apiGroups:
  - ""
  resources:
  - pods/exec
  verbs:
  - create
  - get
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - storagetypes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - test.example.com
  resources:
  - storagetypes/status
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: my-operator-metrics-reader
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: my-operator-proxy-role
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - tokenreviews
  verbs:
  - create
- apiGroups:
  - authorization.k8s.io
  resources:
  - subjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-operator-leader-election-rolebinding
  namespace: my-operator-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: my-operator-leader-election-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-operator-manager-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: my-operator-manager-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-operator-proxy-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: my-operator-proxy-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: v1
data:
  dummyconfigmapkey: dummyconfigmapvalue
  controller_manager_config.yaml: |
    apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
    kind: ControllerManagerConfig
    health:
      healthProbeBindAddress: :8081
    metrics:
      bindAddress: 127.0.0.1:8080
    webhook:
      port: 9443
    leaderElection:
      leaderElect: true
      resourceName: 3a2e09e9.example.com
    rook:
      namespace: rook-ceph
      toolboxPodLabel: rook-ceph-tools
kind: ConfigMap
metadata:
  name: my-operator-manager-config
  namespace: my-operator-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager-metrics-service
  namespace: my-operator-system
spec:
  ports:
  - name: https
    port: 8443
    targetPort: https
  selector:
    control-plane: controller-manager
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager
  namespace: my-operator-system
spec:
  replicas: 1
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      control-plane: controller-manager
  template:
    metadata:
      labels:
        control-plane: controller-manager
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        matchLabelKeys:
          - app
          - pod-template-hash
      containers:
      - args:
        - --secure-listen-address=0.0.0.0:8443
        - --upstream=http://127.0.0.1:8080/
        - --logtostderr=true
        - --v=10
        image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
        name: kube-rbac-proxy
        ports:
        - containerPort: 8443
          name: https
      - args:
        - --health-probe-bind-address=:8081
        - --metrics-bind-address=127.0.0.1:8080
        - --leader-elect
        command:
        - /manager
        volumeMounts:
        - mountPath: /controller_manager_config.yaml
          name: manager-config
          subPath: controller_manager_config.yaml
        - name: secret-volume
          mountPath: /my.ca
        env:
        - name: VAR1
          valueFrom:
            secretKeyRef:
              name: my-operator-secret-vars
              key: VAR1
        - name: VAR2
          value: "ciao"
        - name: VAR3_MY_ENV
          value: "ciao"
        - name: VAR4
          valueFrom:
            configMapKeyRef:
              name: my-operator-configmap-vars
              key: VAR4
        - name: VAR5
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: VAR6
          valueFrom:
            resourceFieldRef:
              resource: limits.cpu
        image: busybox:latest
        imagePullPolicy: Always
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: manager
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: 100m
            memory: 30Mi
          requests:
            cpu: 100m
            memory: 20Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 65532
          seccompProfile:
            type: RuntimeDefault
      securityContext:
        runAsNonRoot: true
      nodeSelector:
        region: east
        type: user-node
      serviceAccountName: my-operator-controller-manager
      terminationGracePeriodSeconds: 10
      volumes:
      - configMap:
          name: my-operator-manager-config
        name: manager-config
      - name: secret-volume
        secret:
          secretName: my-operator-secret-ca
---
apiVersion: v1
data:
  VAR1: bXlfc2VjcmV0X3Zhcl8x
  VAR2: bXlfc2VjcmV0X3Zhcl8y
kind: Secret
metadata:
  name: my-operator-secret-vars
  namespace: my-operator-system
type: opaque
---
apiVersion: v1
data:
  VAR4: value for var4
kind: ConfigMap
metadata:
  name: my-operator-configmap-vars
  namespace: my-operator-system
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-operator-pvc-lim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: cust1-mypool-lim

070701000000AF000081A400000000000000000000000167C8625900006090000000000000000000000000000000000000003700000000helmify-0.4.18/test_data/k8s-operator-kustomize.outputapiVersion: v1
kind: Namespace
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-system
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
    example-annotation: xyz
  creationTimestamp: null
  name: cephvolumes.test.example.com
  labels:
    example-label: my-app 
spec:
  group: test.example.com
  names:
    kind: CephVolume
    listKind: CephVolumeList
    plural: cephvolumes
    singular: cephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.pool
      name: Pool
      type: string
    - description: Storage type
      jsonPath: .status.type
      name: Type
      type: string
    - description: Volume size
      jsonPath: .spec.size
      name: Size
      type: string
    - description: Max number of volume I/O operations per second
      jsonPath: .status.limits.iops
      name: IOPS
      type: string
    - description: true if volume contains latest type,size spec from Ceph
      jsonPath: .status.conditions[?(@.type=="Provided")].status
      name: Provided
      type: string
    - description: true if volume IOPS limits calculated. False indicates error -
        check reason for details
      jsonPath: .status.conditions[?(@.type=="Calculated")].status
      name: Calculated
      type: string
    - description: true if volume IOPS limits applied to volume. False indicates error
        - check reason for details
      jsonPath: .status.conditions[?(@.type=="Limited")].status
      name: Limited
      type: string
    - description: latest resource generation
      jsonPath: .metadata.generation
      name: gen
      type: string
    - description: latest observed generation of Limited condition
      jsonPath: .status.conditions[?(@.type=="Limited")].observedGeneration
      name: Lim-gen
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: CephVolume represents Ceph RBD volume
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: CephVolumeSpec defines the desired state of CephVolume
            properties:
              pool:
                description: Pool - volume pool name
                type: string
              size:
                anyOf:
                - type: integer
                - type: string
                description: Size - volume size
                pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                x-kubernetes-int-or-string: true
            type: object
          status:
            description: CephVolumeStatus defines the observed state of CephVolume
            properties:
              conditions:
                description: 'Conditions represent the latest available observations
                  of an object''s state Known .status.conditions.type are: "Provided".
                  "Calculated", "Limited"'
                items:
                  description: "Condition contains details for one aspect of the current
                    state of this API Resource. --- This struct is intended for direct
                    use as an array at the field path .status.conditions.  For example,
                    type FooStatus struct{     // Represents the observations of a
                    foo's current state.     // Known .status.conditions.type are:
                    \"Available\", \"Progressing\", and \"Degraded\"     // +patchMergeKey=type
                    \    // +patchStrategy=merge     // +listType=map     // +listMapKey=type
                    \    Conditions []metav1.Condition `json:\"conditions,omitempty\"
                    patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`
                    \n     // other fields }"
                  properties:
                    lastTransitionTime:
                      description: lastTransitionTime is the last time the condition
                        transitioned from one status to another. This should be when
                        the underlying condition changed.  If that is not known, then
                        using the time when the API field changed is acceptable.
                      format: date-time
                      type: string
                    message:
                      description: message is a human readable message indicating
                        details about the transition. This may be an empty string.
                      maxLength: 32768
                      type: string
                    observedGeneration:
                      description: observedGeneration represents the .metadata.generation
                        that the condition was set based upon. For instance, if .metadata.generation
                        is currently 12, but the .status.conditions[x].observedGeneration
                        is 9, the condition is out of date with respect to the current
                        state of the instance.
                      format: int64
                      minimum: 0
                      type: integer
                    reason:
                      description: reason contains a programmatic identifier indicating
                        the reason for the condition's last transition. Producers
                        of specific condition types may define expected values and
                        meanings for this field, and whether the values are considered
                        a guaranteed API. The value should be a CamelCase string.
                        This field may not be empty.
                      maxLength: 1024
                      minLength: 1
                      pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
                      type: string
                    status:
                      description: status of the condition, one of True, False, Unknown.
                      enum:
                      - "True"
                      - "False"
                      - Unknown
                      type: string
                    type:
                      description: type of condition in CamelCase or in foo.example.com/CamelCase.
                        --- Many .condition.type values are consistent across resources
                        like Available, but because arbitrary conditions can be useful
                        (see .node.status.conditions), the ability to deconflict is
                        important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
                      maxLength: 316
                      pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
                      type: string
                  required:
                  - lastTransitionTime
                  - message
                  - reason
                  - status
                  - type
                  type: object
                type: array
              limits:
                description: Limits represent calculated IOPS limits
                properties:
                  iops:
                    description: IOPS - desired limit of IO operations per second.
                      See Ceph rbd_qos_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  iopsBurst:
                    description: IOPSBurst - desired burst limit of IO operations.
                      See Ceph rbd_qos_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPS:
                    description: ReadIOPS - desired limit of read operations per second.
                      See Ceph rbd_qos_read_iops_limit property.
                    format: int64
                    minimum: 0
                    type: integer
                  readIOPSBurst:
                    description: ReadIOPSBurst - desired burst limit of read operations.
                      See Ceph rbd_qos_read_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPS:
                    description: WriteIOPS - desired limit of write operations per
                      second. See Ceph rbd_qos_write_iops_limit property
                    format: int64
                    minimum: 0
                    type: integer
                  writeIOPSBurst:
                    description: WriteIOPSBurst - desired burst limit of write operations.
                      See Ceph rbd_qos_write_iops_burst property.
                    format: int64
                    minimum: 0
                    type: integer
                type: object
              type:
                description: Type - volume storage type. See StorageType CRD.
                type: string
            required:
            - conditions
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  creationTimestamp: null
  name: manifestcephvolumes.test.example.com
spec:
  conversion:
    strategy: Webhook
    webhook:
      clientConfig:
        service:
          name: my-operator-webhook-service
          namespace: my-operator-system
          path: /convert
      conversionReviewVersions:
      - v1
  group: test.example.com
  names:
    kind: ManifestCephVolume
    listKind: ManifestCephVolumeList
    plural: manifestcephvolumes
    singular: manifestcephvolume
  scope: Namespaced
  versions:
  - additionalPrinterColumns:
    - description: Ceph RBD pool name
      jsonPath: .spec.poolName
      name: PoolName
      type: string
    - description: Sync interval in seconds
      jsonPath: .spec.interval
      name: Interval
      type: string
    - description: Last update time
      jsonPath: .status.lastUpdate
      name: LastUpdate
      type: string
    name: v1alpha1
    schema:
      openAPIV3Schema:
        description: ManifestCephVolume monitors given ceph pool and manifests containing
          volumes as CephVolume CR
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: ManifestCephVolumeSpec defines the desired state of ManifestCephVolume
            properties:
              interval:
                description: Interval - Ceph pool polling interval
                format: int32
                minimum: 60
                type: integer
              poolName:
                description: PoolName name of Ceph RBD pool to get volumes
                type: string
            required:
            - interval
            type: object
          status:
            description: ManifestCephVolumeStatus defines the observed state of ManifestCephVolume
            properties:
              lastUpdate:
                description: LastUpdate - time of last successful volumes update
                format: date-time
                type: string
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
status:
  acceptedNames:
    kind: ""
    plural: ""
  conditions: []
  storedVersions: []
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-operator-controller-manager
  namespace: my-operator-system
  annotations:
    k8s.acme.org/some-meta-data: "ACME Inc."
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-operator-leader-election-role
  namespace: my-operator-system
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: my-operator-manager-aggregated-role
aggregationRule:
  clusterRoleSelectors:
  - matchExpressions:
    - key: app.kubernetes.io/instance
      operator: In
      values:
      - my-operator
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  creationTimestamp: null
  name: my-operator-manager-role
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
- apiGroups:
  - ""
  resources:
  - pods/exec
  verbs:
  - create
  - get
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - cephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/finalizers
  verbs:
  - update
- apiGroups:
  - test.example.com
  resources:
  - manifestcephvolumes/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - test.example.com
  resources:
  - storagetypes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - test.example.com
  resources:
  - storagetypes/status
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: my-operator-metrics-reader
rules:
- nonResourceURLs:
  - /metrics
  verbs:
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: my-operator-proxy-role
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - tokenreviews
  verbs:
  - create
- apiGroups:
  - authorization.k8s.io
  resources:
  - subjectaccessreviews
  verbs:
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: my-operator-leader-election-rolebinding
  namespace: my-operator-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: my-operator-leader-election-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-operator-manager-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: my-operator-manager-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-operator-proxy-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: my-operator-proxy-role
subjects:
- kind: ServiceAccount
  name: my-operator-controller-manager
  namespace: my-operator-system
---
apiVersion: v1
data:
  dummyconfigmapkey: dummyconfigmapvalue
  controller_manager_config.yaml: |
    apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
    kind: ControllerManagerConfig
    health:
      healthProbeBindAddress: :8081
    metrics:
      bindAddress: 127.0.0.1:8080
    webhook:
      port: 9443
    leaderElection:
      leaderElect: true
      resourceName: 3a2e09e9.example.com
    rook:
      namespace: rook-ceph
      toolboxPodLabel: rook-ceph-tools
kind: ConfigMap
metadata:
  name: my-operator-manager-config
  namespace: my-operator-system
---
apiVersion: v1
kind: Service
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager-metrics-service
  namespace: my-operator-system
spec:
  ports:
  - name: https
    port: 8443
    targetPort: https
  selector:
    control-plane: controller-manager
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    control-plane: controller-manager
  name: my-operator-controller-manager
  namespace: my-operator-system
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
  selector:
    matchLabels:
      control-plane: controller-manager
  template:
    metadata:
      labels:
        control-plane: controller-manager
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: kubernetes.io/hostname
        whenUnsatisfiable: DoNotSchedule
        matchLabelKeys:
          - app
          - pod-template-hash
      imagePullSecrets:
        - name: my-operator-secret-registry-credentials
      containers:
      - args:
        - --secure-listen-address=0.0.0.0:8443
        - --upstream=http://127.0.0.1:8080/
        - --logtostderr=true
        - --v=10
        image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
        name: kube-rbac-proxy
        ports:
        - containerPort: 8443
          name: https
      - args:
        - --health-probe-bind-address=:8081
        - --metrics-bind-address=127.0.0.1:8080
        - --leader-elect
        command:
        - /manager
        volumeMounts:
        - mountPath: /controller_manager_config.yaml
          name: manager-config
          subPath: controller_manager_config.yaml
        - name: secret-volume
          mountPath: /my.ca
        env:
        - name: VAR1
          valueFrom:
            secretKeyRef:
              name: my-operator-secret-vars
              key: VAR1
        - name: VAR2
          value: "ciao"
        - name: VAR3_MY_ENV
          value: "ciao"
        - name: VAR4
          valueFrom:
            configMapKeyRef:
              name: my-operator-configmap-vars
              key: VAR4
        - name: VAR5
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: VAR6
          valueFrom:
            resourceFieldRef:
              resource: limits.cpu
        image: controller:latest
        imagePullPolicy: Always
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8081
          initialDelaySeconds: 15
          periodSeconds: 20
        name: manager
        readinessProbe:
          httpGet:
            path: /readyz
            port: 8081
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          limits:
            cpu: 100m
            memory: 30Mi
          requests:
            cpu: 100m
            memory: 20Mi
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 65532
          seccompProfile:
            type: RuntimeDefault
      securityContext:
        runAsNonRoot: true
      nodeSelector:
        region: east
        type: user-node
      serviceAccountName: my-operator-controller-manager
      terminationGracePeriodSeconds: 10
      volumes:
      - configMap:
          name: my-operator-manager-config
        name: manager-config
      - name: secret-volume
        secret:
          secretName: my-operator-secret-ca

---
apiVersion: v1
kind: Service
metadata:
  name: my-operator-webhook-service
  namespace: my-operator-system
spec:
  ports:
  - port: 443
    targetPort: 9443
  selector:
    control-plane: controller-manager
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-operator-serving-cert
  namespace: my-operator-system
spec:
  dnsNames:
  - my-operator-webhook-service.my-operator-system.svc
  - my-operator-webhook-service.my-operator-system.svc.cluster.local
  issuerRef:
    kind: Issuer
    name: my-operator-selfsigned-issuer
  secretName: webhook-server-cert
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: my-operator-selfsigned-issuer
  namespace: my-operator-system
spec:
  selfSigned: {}
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  name: my-operator-validating-webhook-configuration
webhooks:
- admissionReviewVersions:
  - v1
  - v1beta1
  clientConfig:
    service:
      name: my-operator-webhook-service
      namespace: my-operator-system
      path: /validate-ceph-example-com-v1alpha1-volume
  failurePolicy: Fail
  name: vvolume.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1alpha1
    operations:
    - CREATE
    - UPDATE
    resources:
    - volumes
  sideEffects: None
---
apiVersion: v1
data:
  ca.crt: |
    c3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3
    VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3Vw
    ZXJsb25ndGVzdGNydC0Kc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cG
    VybG9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVy
    bG9uZ3Rlc3RjcnQKc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG
    9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9u
    Z3Rlc3RjcnQ=
kind: Secret
metadata:
  name: my-operator-secret-ca
  namespace: my-operator-system
type: opaque
---
apiVersion: v1
data:
  .dockerconfigjson: |
    ewogICAgImF1dGhzIjogewogICAgICAgICJmb28uYmFyLmlvIjogewogICAgICAgICAgIC
    AidXNlcm5hbWUiOiAidXNlcm5hbWUiLAogICAgICAgICAgICAicGFzc3dvcmQiOiAic2Vj
    cmV0IiwKICAgICAgICAgICAgImF1dGgiOiAiZFhObGNtNWhiV1U2YzJWamNtVjAiCiAgIC
    AgICAgfQogICAgfQp9
kind: Secret
metadata:
  name: my-operator-secret-registry-credentials
  namespace: my-operator-system
type: kubernetes.io/dockerconfigjson
---
apiVersion: v1
data:
  VAR1: bXlfc2VjcmV0X3Zhcl8x
  VAR2: bXlfc2VjcmV0X3Zhcl8y
kind: Secret
metadata:
  name: my-operator-secret-vars
  namespace: my-operator-system
type: opaque
---
apiVersion: v1
data:
  VAR4: value for var4
kind: ConfigMap
metadata:
  name: my-operator-configmap-vars
  namespace: my-operator-system
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-operator-pvc-lim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: cust1-mypool-lim
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  annotations:
    cert-manager.io/inject-ca-from: my-operator-system/my-operator-serving-cert
  name: my-operator-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
  - v1
  clientConfig:
    service:
      name: my-operator-webhook-service
      namespace: my-operator-system
      path: /mutate-ceph-example-com-v1-mycluster
  failurePolicy: Fail
  name: mmycluster.kb.io
  rules:
  - apiGroups:
    - test.example.com
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - myclusters
  sideEffects: None
070701000000B0000081A400000000000000000000000167C86259000021BE000000000000000000000000000000000000002900000000helmify-0.4.18/test_data/sample-app.yamlapiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp
  name: myapp
  namespace: my-ns
spec:
  replicas: 3
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      initContainers:
        - name: init-container
          image: bash:latest
          command: ["/bin/sh", "-c", "echo 'Initializing container...'"]
      containers:
        - name: app
          args:
            - --health-probe-bind-address=:8081
            - --metrics-bind-address=127.0.0.1:8080
            - --leader-elect
          command:
            - /manager
          volumeMounts:
            - mountPath: /my_config.properties
              name: manager-config
              subPath: my_config.properties
            - name: secret-volume
              mountPath: /my.ca
            - name: props
              mountPath: /etc/props
            - name: sample-pv-storage
              mountPath: "/usr/share/nginx/html"
          env:
            - name: VAR1
              valueFrom:
                secretKeyRef:
                  name: my-secret-vars
                  key: VAR1
            - name: VAR2
              valueFrom:
                secretKeyRef:
                  name: my-secret-vars
                  key: VAR2
            - name: APP_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['app.kubernetes.io/name']
            - name: INSTANCE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['app.kubernetes.io/instance']
          image: controller:latest
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8081
            initialDelaySeconds: 15
            periodSeconds: 20
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8081
            initialDelaySeconds: 5
            periodSeconds: 10
          resources:
            limits:
              cpu: 100m
              memory: 30Mi
            requests:
              cpu: 100m
              memory: 20Mi
          securityContext:
            allowPrivilegeEscalation: false
        - name: proxy-sidecar
          args:
            - --secure-listen-address=0.0.0.0:8443
            - --v=10
          image: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0
          ports:
            - containerPort: 8443
              name: https
      securityContext:
        runAsNonRoot: true
        fsGroup: 20000
        runAsUser: 65532
      nodeSelector:
        region: east
        type: user-node
      terminationGracePeriodSeconds: 10
      volumes:
        - configMap:
            name: my-config
          name: manager-config
        - configMap:
            name: my-config-props
          name: props
        - name: secret-volume
          secret:
            secretName: my-secret-ca
        - name: sample-pv-storage
          persistentVolumeClaim:
            claimName: my-sample-pv-claim
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-sample-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi
    limits:
      storage: 5Gi
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myapp-service
  namespace: my-ns
spec:
  ports:
    - name: https
      port: 8443
      targetPort: https
  selector:
    app: myapp
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp
  name: myapp-lb-service
  namespace: my-ns
spec:
  ports:
    - name: https
      port: 8443
      targetPort: https
  selector:
    app: myapp
  type: LoadBalancer
  loadBalancerSourceRanges:
  - 10.0.0.0/8
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - http:
        paths:
          - path: /testpath
            pathType: Prefix
            backend:
              service:
                name: myapp-service
                port:
                  number: 8443
---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret-ca
  namespace: my-ns
type: opaque
data:
  ca.crt: |
    c3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3
    VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9uZ3Rlc3RjcnQtc3Vw
    ZXJsb25ndGVzdGNydC0Kc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cG
    VybG9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVy
    bG9uZ3Rlc3RjcnQKc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG
    9uZ3Rlc3RjcnQtc3VwZXJsb25ndGVzdGNydC1zdXBlcmxvbmd0ZXN0Y3J0LXN1cGVybG9u
    Z3Rlc3RjcnQ=
---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret-vars
  namespace: my-ns
type: opaque
data:
  VAR1: bXlfc2VjcmV0X3Zhcl8x
  VAR2: bXlfc2VjcmV0X3Zhcl8y
  ELASTIC_FOOBAR_HUNTER123_MEOWTOWN_VERIFY: bXlfc2VjcmV0X3Zhcl8y
stringData:
  str: |
    some big not so secret string with
    multiple lines
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
  namespace: my-ns
immutable: true
data:
  dummyconfigmapkey: dummyconfigmapvalue
  my_config.properties: |
    health.healthProbeBindAddress=8081
    metrics.bindAddress=127.0.0.1:8080
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config-props
  namespace: my-ns
data:
  my.prop1: "1"
  my.prop2: "val 1"
  my.prop3: "true"
  myval.yaml: |
    apiVersion: clickhouse.altinity.com/v1
    kind: ClickHouseInstallationTemplate
    metadata:
      name: default-oneperhost-pod-template
    spec:
      templates:
        podTemplates: 
          - name: default-oneperhost-pod-template
            distribution: "OnePerHost"
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
---
apiVersion: batch/v1
kind: Job
metadata:
  name: batch-job
spec:
  template:
    spec:
      containers:
        - name: pi
          image: perl:5.34.0
          command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cron-job
spec:
  schedule: "* * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox:1.28
              imagePullPolicy: IfNotPresent
              command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
    - port: 80
      name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: registry.k8s.io/nginx-slim:0.8
          ports:
            - containerPort: 80
              name: web
          volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: www
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 1Gi
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  labels:
    app: nginx
  name: myapp-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: nginx
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!875 blocks
openSUSE Build Service is sponsored by