[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: kwsorensen\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Command run [e.g. ./kurt all]\n2. Information about run environment\nIncluding\n - OS: [e.g. Ubuntu]\n - kurt cli version [e.g. v0.1.0]\n - Confirmation of kubectl configuration/permissions\n \n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: kwsorensen\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--  Thanks for sending a pull request!  Here are some tips for you:\n\n1. Please file an issue before making a pull request.\n2. Clarification on feature functionality should be done on the Issues page and implementation details should be discussed on the Pull Request.\n-->\n\n#### What this PR does / why we need it:\n\n#### Which issue(s) this PR fixes:\n<!--\n*Automatically closes linked issue when PR is merged.\nUsage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.\n_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*\n-->\nFixes #<issue number> \n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"gomod\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"daily\"\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "on:\n  pull_request:\n    branches:\n      - main\n  push:\n    branches:\n      - \"main\"\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  build:\n    runs-on: ubuntu-20.04\n    steps:\n      - uses: actions/setup-go@v2\n        with:\n          go-version: \"1.21\"\n      - uses: actions/checkout@v2\n      - run: go build\n\n  test:\n    runs-on: ubuntu-20.04\n    steps:\n      - uses: actions/setup-go@v2\n        with:\n          go-version: \"1.21\"\n      - uses: actions/checkout@v2\n      - run: go test ./cmd -v\n\n  lint:\n    runs-on: ubuntu-20.04\n    steps:\n      - uses: actions/setup-go@v2\n        with:\n          go-version: \"1.21\"\n      - uses: actions/checkout@v2\n      - run: |\n          if\n            test -z $(gofmt -l .); then\n            echo \"All golang files formatted correctly 👍️\";\n          else\n            echo \"❗️ Golang formatting issues:\"; gofmt -l .; exit 1\n          fi"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ main ]\n  schedule:\n    - cron: '44 7 * * 6'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'go' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://git.io/codeql-language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v2\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v1\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v1\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v1\n"
  },
  {
    "path": ".github/workflows/e2e.yml",
    "content": "name: e2e tests\non:\n  pull_request:\n  workflow_dispatch:\njobs:\n  run-e2e-tests:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        include:\n          # get these here: https://github.com/kubernetes-sigs/kind/releases\n          - version: \"1.32\"\n            image: kindest/node:v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027\n          - version: \"1.31\"\n            image: kindest/node:v1.31.4@sha256:2cb39f7295fe7eafee0842b1052a599a4fb0f8bcf3f83d96c7f4864c357c6c30\n          - version: \"1.30\"\n            image: kindest/node:v1.30.8@sha256:17cd608b3971338d9180b00776cb766c50d0a0b6b904ab4ff52fd3fc5c6369bf\n          - version: \"1.29\"\n            image: kindest/node:v1.29.2@sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245\n          - version: \"1.28\"\n            image: kindest/node:v1.28.7@sha256:9bc6c451a289cf96ad0bbaf33d416901de6fd632415b076ab05f5fa7e4f65c58\n          - version: \"1.27\"\n            image: kindest/node:v1.27.11@sha256:681253009e68069b8e01aad36a1e0fa8cf18bb0ab3e5c4069b2e65cafdd70843\n          - version: \"1.26\"\n            image: kindest/node:v1.26.14@sha256:5d548739ddef37b9318c70cb977f57bf3e5015e4552be4e27e57280a8cbb8e4f\n    steps:\n      - name: Create k8s Kind Cluster - ${{ matrix.version }}\n        uses: helm/kind-action@v1.5.0\n        with:\n          node_image: ${{ matrix.image }}\n      - name: Show cluster version\n        run: kubectl version\n      - uses: actions/setup-go@v2\n        with:\n          go-version: \"1.21\"\n      - uses: actions/checkout@v2\n      - run: go build\n      - name: e2e test\n        run: tests/e2e.sh"
  },
  {
    "path": ".github/workflows/go-releaser.yml",
    "content": "name: goreleaser\n\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n\njobs:\n  goreleaser:\n    runs-on: ubuntu-latest\n    steps:\n      -\n        name: Checkout\n        uses: actions/checkout@v2\n        with:\n          fetch-depth: 0\n      -\n        name: Set up Go\n        uses: actions/setup-go@v2\n        with:\n          go-version: 1.21\n      \n      - name: Anchore SBOM action\n        uses: anchore/sbom-action@v0\n      \n      -\n        name: Run GoReleaser\n        uses: goreleaser/goreleaser-action@v2\n        with:\n          distribution: goreleaser\n          version: latest\n          args: release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      \n      -\n        name: Update new version in krew-index\n        uses: rajatjindal/krew-release-bot@v0.0.40\n"
  },
  {
    "path": ".gitignore",
    "content": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n.vscode/\n**/__debug_bin\nkurt\n!kurt/\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out"
  },
  {
    "path": ".goreleaser.yml",
    "content": "builds:\n  - id: kurt\n    goos:\n      - darwin\n      - linux\n      - windows\n    goarch:\n      - amd64\n      - arm64\n    ldflags: -s -w\n      -X kurt/internal/version.version={{.Version}}\n      -X kurt/internal/version.gitSHA={{.Commit}}\n      -X kurt/internal/version.buildTime={{.Date}}\n      -extldflags \"-static\"\nchecksum:\n  name_template: \"{{ .ProjectName }}_checksums.txt\"\nsboms: # https://goreleaser.com/customization/sbom/\n  - artifacts: archive\narchives:\n  - id: kurt\n    builds:\n      - kurt\n    format: tar.gz\n    format_overrides:\n      - goos: windows\n        format: zip\n    name_template: \"{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}\""
  },
  {
    "path": ".krew.yaml",
    "content": "apiVersion: krew.googlecontainertools.github.com/v1alpha2\nkind: Plugin\nmetadata:\n  name: kurt\nspec:\n  version: {{ .TagName }}\n  platforms:\n  - selector:\n      matchLabels:\n        os: linux\n        arch: amd64\n    {{addURIAndSha \"https://github.com/soraro/kurt/releases/download/{{ .TagName }}/kurt_linux_amd64.tar.gz\" .TagName }}\n    files:\n    - from: kurt\n      to: .\n    - from: LICENSE\n      to: .\n    bin: kurt\n  - selector:\n      matchLabels:\n        os: darwin\n        arch: amd64\n    {{addURIAndSha \"https://github.com/soraro/kurt/releases/download/{{ .TagName }}/kurt_darwin_amd64.tar.gz\" .TagName }}\n    files:\n    - from: kurt\n      to: .\n    - from: LICENSE\n      to: .\n    bin: kurt\n  - selector:\n      matchLabels:\n        os: darwin\n        arch: arm64\n    {{addURIAndSha \"https://github.com/soraro/kurt/releases/download/{{ .TagName }}/kurt_darwin_arm64.tar.gz\" .TagName }}\n    files:\n    - from: kurt\n      to: .\n    - from: LICENSE\n      to: .\n    bin: kurt\n  - selector:\n      matchLabels:\n        os: linux\n        arch: arm64\n    {{addURIAndSha \"https://github.com/soraro/kurt/releases/download/{{ .TagName }}/kurt_linux_arm64.tar.gz\" .TagName }}\n    files:\n    - from: kurt\n      to: .\n    - from: LICENSE\n      to: .\n    bin: kurt\n  - selector:\n      matchLabels:\n        os: windows\n        arch: amd64\n    {{addURIAndSha \"https://github.com/soraro/kurt/releases/download/{{ .TagName }}/kurt_windows_amd64.zip\" .TagName }}\n    files:\n    - from: kurt.exe\n      to: .\n    - from: LICENSE\n      to: .\n    bin: kurt.exe\n  shortDescription: Find what's restarting and why\n  homepage: https://github.com/soraro/kurt\n  description: |\n    Use kurt to see pods that are restarting in your cluster and get further context to issues by grouping the results.\n    Top 5 results from all groupings:\n    kubectl kurt all\n\n    Top 5 nodes with restarting pods:\n    kubectl kurt nodes\n\n    All restarting pods in the test namespace:\n    kubectl kurt pods -c 0 -n test\n\n    Help:\n    kubectl kurt -h\n\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[@kwsorensen](https://github.com/kwsorensen) or [@aro5000](https://github.com/aro5000).\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nCreate an Issue or Create a PR\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Kyle Sorensen, Aaron Stults\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# kurt\n```\nkurt: KUbernetes Restart Tracker\n\nA restart tracker that gives context to what is restarting in your cluster\n\nUsage:\n  kurt [command]\n\nAvailable Commands:\n  all         Print all groupings collected by kurt!\n  completion  generate the autocompletion script for the specified shell\n  help        Help about any command\n  labels      Only print restart counts grouped by labels\n  namespaces  Only print namespace-wide restart counts\n  nodes       Only print node restart counts\n  pods        Only print pod restart counts\n  version     Print the current version and exit\n\nFlags:\n  -h, --help                help for kurt\n  -l, --label strings       Specify multiple times for the label keys you want to see.\n                            For example: \"kurt all -l app\"\n  -c, --limit int           Limit the number of resources you want to see. Set limit to 0 for no limits. Must be positive.\n                            For example: \"kurt all -c=10\" (default 5)\n  -n, --namespace strings   Specify namespace for kurt to collect restart metrics.\n                            Leave blank to collect in all namespaces.\n  -o, --output string       Specify output type. Options are: json, yaml, standard\n                            For example: \"kurt all -o json\" (default \"standard\")\n\nUse \"kurt [command] --help\" for more information about a command.\n```\n\n# Install\nHead over to our [releases page](https://github.com/soraro/kurt/releases/latest) or run as a `kubectl` plugin with [krew](https://krew.sigs.k8s.io/)\n```\nkubectl krew install kurt\n```\n\nEasily install krew and kurt with the following:\n```\ncurl https://krew.sh/kurt | bash\n```\n\n# Examples\nShow the top 5 highest restart counts grouped by `Namespace`, `Node`, `Label`, and `Pod`:\n```\n$ kurt all\n\nkurt: KUbernetes Restart Tracker\n\n==========\n\n Namespace      Restarts\n\n default        2\n test           1\n kube-system    0\n\n==========\n\n Node           Restarts\n\n minikube-m02   2\n minikube-m03   1\n minikube       0\n\n==========\n\n Label                                          Restarts\n\n run:nginx                                      3\n component:etcd                                 0\n k8s-app:kube-proxy                             0\n addonmanager.kubernetes.io/mode:Reconcile      0\n integration-test:storage-provisioner           0\n\n==========\n\n Pod                            Namespace       Restarts\n\n nginx                          default         2\n nginx                          test            1\n kube-apiserver-minikube        kube-system     0\n storage-provisioner            kube-system     0\n etcd-minikube                  kube-system     0\n```\n\nShow more results:\n```\nkurt all -c 10\n\n# use -c 0 if you want to show all results\n```\n\nShow which node has the most restarted pods:\n```\nkurt no\n```\n\nShow top 20 pod restart counts in the `default` namespace which also have the `app` label key:\n```\nkurt po -n default -l app -c 20\n```\n\nGet help:\n```\nkurt -h\n```\n\nStructured output:\n```\n# With structured output you could use a script like this to delete the top rebooting pod\n\nJSON=$(kurt pods -o json)\nPOD=$(echo $JSON | jq -r .pods[0].name)\nNS=$(echo $JSON | jq -r .pods[0].namespace)\nkubectl delete pod $POD -n $NS\n```\n\n# Permissions\nAs seen in the [`cmd/collect.go` file](https://github.com/soraro/kurt/blob/main/cmd/collect.go) the only permission required for kurt is `pods/list`.\n\n# Requirements\nGo Version 1.21\n\n# Building\n```\ngo build .\n```\nOutputs a `kurt` binary\n\n# Testing\n```\ngo test ./cmd -v\n```\n"
  },
  {
    "path": "cmd/auth.go",
    "content": "package cmd\n\nimport (\n\t\"k8s.io/client-go/kubernetes\"\n\t_ \"k8s.io/client-go/plugin/pkg/client/auth\"\n\t\"k8s.io/client-go/tools/clientcmd\"\n)\n\n// Handle setting up cluster auth and return clientset\nfunc auth() *kubernetes.Clientset {\n\n\tloadingRules := clientcmd.NewDefaultClientConfigLoadingRules()\n\tconfigOverrides := &clientcmd.ConfigOverrides{}\n\n\tkubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)\n\tconfig, err := kubeConfig.ClientConfig()\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\n\tclientset, err := kubernetes.NewForConfig(config)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\n\treturn clientset\n\n}\n"
  },
  {
    "path": "cmd/collect.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n\t\"k8s.io/client-go/kubernetes\"\n)\n\nfunc collect(clientset *kubernetes.Clientset, namespace []string, labels []string) {\n\n\tif limitFlag < 0 {\n\t\tlog.Fatal(\"FATAL CONFIGURATION: --limit flag value must not be negative.\")\n\t}\n\n\tif !(output == \"standard\" || output == \"yaml\" || output == \"json\") {\n\t\tlog.Fatal(\"FATAL CONFIGURATION: --output flag can only be: standard, json, yaml\")\n\t}\n\n\tfor _, ns := range namespace {\n\t\tfor _, lb := range labels {\n\t\t\tpods, err := clientset.CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: lb})\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatal(err.Error())\n\t\t\t}\n\n\t\t\tfor _, v := range pods.Items {\n\t\t\t\tinitializeContainerMap(v.ObjectMeta.Name, v.ObjectMeta.Namespace)\n\t\t\t\trestarts := int32(0)\n\t\t\t\tfor _, vv := range v.Status.ContainerStatuses {\n\t\t\t\t\trestarts += vv.RestartCount\n\t\t\t\t\ttrackContainers(v.ObjectMeta.Name, v.ObjectMeta.Namespace, vv.Name, vv.RestartCount)\n\t\t\t\t}\n\t\t\t\ttrackPods(v.ObjectMeta.Name, v.ObjectMeta.Namespace, restarts)\n\t\t\t\ttrackNamespaces(v.ObjectMeta.Namespace, restarts)\n\t\t\t\ttrackLabels(labels, v.ObjectMeta.Labels, restarts)\n\t\t\t\ttrackNodes(v.Spec.NodeName, restarts)\n\t\t\t}\n\t\t}\n\t}\n\tshowResults()\n\n}\n\nfunc trackNamespaces(namespace string, count int32) {\n\tnamespaceTracker[namespace] += count\n}\n\nfunc trackNodes(node string, count int32) {\n\tnodeTracker[node] += count\n}\n\nfunc trackPods(pod, namespace string, count int32) {\n\tpodTracker[namespace+\":\"+pod] = count\n}\n\nfunc trackContainers(pod, namespace, container string, count int32) {\n\tcontainerTracker[namespace+\":\"+pod][container] = count\n}\n\nfunc initializeContainerMap(pod, namespace string) {\n\tcontainerTracker[namespace+\":\"+pod] = make(map[string]int32)\n}\n\n// plabels = Pod Labels\n// tlabels = (User-defined) tracking labels\nfunc trackLabels(tlabels []string, plabels map[string]string, count int32) {\n\t// range through all the labels specified in the -l CLI flag\n\tfor _, l := range tlabels {\n\t\t// range through plabels to see if any match the user specified labels. If so, add it to the map\n\t\t// the default value \"*\" will match everything\n\t\tfor k, v := range plabels {\n\t\t\tif l == k || l == \"\" {\n\t\t\t\tlabelTracker[k+\":\"+v] += count\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cmd/collect_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n)\n\nfunc TestTrackNamespaces(t *testing.T) {\n\ttrackNamespaces(\"ns1\", 5)\n\ttrackNamespaces(\"ns1\", 2)\n\n\tif namespaceTracker[\"ns1\"] != int32(7) {\n\t\tt.Errorf(\"ns1 namespace expected to have a count of 7 but instead shows: %v\", namespaceTracker[\"ns1\"])\n\t}\n}\n\nfunc TestTrackNodes(t *testing.T) {\n\ttrackNodes(\"node01\", 5)\n\ttrackNodes(\"node01\", 2)\n\ttrackNodes(\"node02\", 2)\n\n\tif nodeTracker[\"node01\"] != int32(7) {\n\t\tt.Errorf(\"node01 node expected to have a count of 7 but instead shows: %v\", nodeTracker[\"node01\"])\n\t}\n}\n\nfunc TestTrackPods(t *testing.T) {\n\t// Test that a pod with the same name in a different namespace is held uniquely in the map\n\ttrackPods(\"pod1\", \"default\", 3)\n\ttrackPods(\"pod1\", \"other\", 2)\n\tif podTracker[\"default:pod1\"] != 3 {\n\t\tt.Errorf(\"pod1 pod expected to have a count of 3 but instead shows: %v\", podTracker[\"pod1\"])\n\t}\n}\n\nfunc TestTrackContainers(t *testing.T) {\n\tinitializeContainerMap(\"pod1\", \"default\")\n\ttrackContainers(\"pod1\", \"default\", \"container1\", 5)\n\tif containerTracker[\"default:pod1\"][\"container1\"] != 5 {\n\t\tt.Errorf(\"pod1/container1 expected to have a count of 5 but instead shows: %v\", containerTracker)\n\t}\n}\n\nfunc TestTrackLabels(t *testing.T) {\n\ttlabels := []string{\"app\", \"k8s-app\"}\n\tplabelsA := map[string]string{\n\t\t\"app\":   \"app1\",\n\t\t\"other\": \"label\",\n\t}\n\tplabelsB := map[string]string{\n\t\t\"k8s-app\": \"app2\",\n\t}\n\n\ttrackLabels(tlabels, plabelsA, 3)\n\ttrackLabels(tlabels, plabelsB, 5)\n\n\t// other:label should not exist because it is not defined in tlabels\n\tif labelTracker[\"other:label\"] != int32(0) {\n\t\tt.Errorf(\"other:label should not exist because it was not defined in user-defined tlabels\")\n\t}\n\n\tif labelTracker[\"app:app1\"] != int32(3) {\n\t\tt.Errorf(\"app:app1 should be equal to 3 since it is defined in the tlabels but instead shows: %v\", labelTracker[\"app:app1\"])\n\t}\n\n\tif labelTracker[\"k8s-app:app2\"] != int32(5) {\n\t\tt.Errorf(\"ks-app:app2 should be equal to 5 since it is defined in the tlabels but instead shows: %v\", labelTracker[\"k8s-app:app2\"])\n\t}\n}\n"
  },
  {
    "path": "cmd/commands.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"github.com/spf13/cobra\"\n\t\"kurt/internal/version\"\n)\n\nvar cmdNamespaces = &cobra.Command{\n\tUse:     \"namespaces\",\n\tShort:   \"Only print namespace-wide restart counts\",\n\tLong:    \"Only print namespace-wide restart counts\",\n\tAliases: []string{\"ns\"},\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tprintNS = true\n\t\tprintAll = false\n\t\tclientset := auth()\n\t\tcollect(clientset, inamespace, ilabels)\n\t},\n}\n\nvar cmdNodes = &cobra.Command{\n\tUse:     \"nodes\",\n\tShort:   \"Only print node restart counts\",\n\tLong:    \"Only print node restart counts\",\n\tAliases: []string{\"no\", \"node\"},\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tprintNode = true\n\t\tprintAll = false\n\t\tclientset := auth()\n\t\tcollect(clientset, inamespace, ilabels)\n\t},\n}\n\nvar cmdPods = &cobra.Command{\n\tUse:     \"pods\",\n\tShort:   \"Only print pod restart counts\",\n\tLong:    \"Only print pod restart counts\",\n\tAliases: []string{\"po\"},\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tprintPods = true\n\t\tprintAll = false\n\t\tclientset := auth()\n\t\tcollect(clientset, inamespace, ilabels)\n\t},\n}\n\nvar cmdLabels = &cobra.Command{\n\tUse:   \"labels\",\n\tShort: \"Only print restart counts grouped by labels\",\n\tLong:  \"Only print restart counts grouped by labels\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tprintLabel = true\n\t\tprintAll = false\n\t\tclientset := auth()\n\t\tcollect(clientset, inamespace, ilabels)\n\t},\n}\n\nvar cmdAll = &cobra.Command{\n\tUse:   \"all\",\n\tShort: \"Print all groupings collected by kurt!\",\n\tLong:  \"Print all groupings collected by kurt!\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tprintAll = true\n\t\tclientset := auth()\n\t\tcollect(clientset, inamespace, ilabels)\n\t},\n}\n\nvar cmdVersion = &cobra.Command{\n\tUse:   \"version\",\n\tShort: \"Print the current version and exit\",\n\tLong:  `Print the current version and exit`,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tfmt.Printf(\"kurt:  %s\\n\", version.Version())\n\t},\n}\n\nfunc init() {\n\trootCmd.AddCommand(cmdNamespaces)\n\trootCmd.AddCommand(cmdNodes)\n\trootCmd.AddCommand(cmdPods)\n\trootCmd.AddCommand(cmdLabels)\n\trootCmd.AddCommand(cmdAll)\n\trootCmd.AddCommand(cmdVersion)\n}\n"
  },
  {
    "path": "cmd/constants.go",
    "content": "package cmd\n\nvar namespaceTracker = make(map[string]int32)\nvar nodeTracker = make(map[string]int32)\nvar podTracker = make(map[string]int32)\nvar labelTracker = make(map[string]int32)\nvar containerTracker = make(map[string]map[string]int32)\n\nvar printAll bool\nvar printNS bool\nvar printNode bool\nvar printPods bool\nvar printLabel bool\n"
  },
  {
    "path": "cmd/printer.go",
    "content": "package cmd\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\n\t\"gopkg.in/yaml.v2\"\n)\n\ntype StructuredOutput struct {\n\tNamespaces ItemList `yaml:\"namespaces,omitempty\" json:\"namespaces,omitempty\"`\n\tNodes      ItemList `yaml:\"nodes,omitempty\" json:\"nodes,omitempty\"`\n\tLabels     ItemList `yaml:\"labels,omitempty\" json:\"labels,omitempty\"`\n\tPods       ItemList `yaml:\"pods,omitempty\" json:\"pods,omitempty\"`\n}\n\nfunc showResults() {\n\tvar so StructuredOutput\n\tw := new(tabwriter.Writer)\n\t// minwidth, tabwidth, padding, padchar, flags\n\tw.Init(os.Stdout, 8, 8, 1, '\\t', 0)\n\n\tif output == \"standard\" {\n\t\tfmt.Printf(\"kurt: KUbernetes Restart Tracker\")\n\t}\n\n\tif printNS || printAll {\n\t\tso.Namespaces = returnSortedLimit(namespaceTracker, limitFlag, false, nil)\n\t\tif output == \"standard\" {\n\t\t\tfmt.Println(\"\\n\\n==========\")\n\t\t\tfmt.Fprintf(w, \"\\n Namespace\\tRestarts\\t\")\n\t\t\tfmt.Fprintf(w, \"\\n \\t\\t\")\n\t\t\tfor _, v := range so.Namespaces {\n\t\t\t\tfmt.Fprintf(w, \"\\n %v\\t%v\\t\", v.Name, v.Count)\n\t\t\t}\n\t\t\tw.Flush()\n\t\t}\n\t}\n\n\tif printNode || printAll {\n\t\tso.Nodes = returnSortedLimit(nodeTracker, limitFlag, false, nil)\n\t\tif output == \"standard\" {\n\t\t\tfmt.Println(\"\\n\\n==========\")\n\t\t\tfmt.Fprintf(w, \"\\n Node\\tRestarts\\t\")\n\t\t\tfmt.Fprintf(w, \"\\n \\t\\t\")\n\t\t\tfor _, v := range so.Nodes {\n\t\t\t\tfmt.Fprintf(w, \"\\n %v\\t%v\\t\", v.Name, v.Count)\n\t\t\t}\n\t\t\tw.Flush()\n\t\t}\n\t}\n\n\tif printLabel || printAll {\n\t\tif len(labelTracker) > 0 {\n\t\t\tso.Labels = returnSortedLimit(labelTracker, limitFlag, false, nil)\n\t\t\tif output == \"standard\" {\n\t\t\t\tfmt.Println(\"\\n\\n==========\")\n\t\t\t\tfmt.Fprintf(w, \"\\n Label\\tRestarts\\t\")\n\t\t\t\tfmt.Fprintf(w, \"\\n \\t\\t\")\n\t\t\t\tfor _, v := range so.Labels {\n\t\t\t\t\tfmt.Fprintf(w, \"\\n %v\\t%v\\t\", v.Name, v.Count)\n\t\t\t\t}\n\t\t\t\tw.Flush()\n\t\t\t}\n\t\t}\n\t}\n\n\tif printPods || printAll {\n\t\tso.Pods = returnSortedLimit(podTracker, limitFlag, true, containerTracker)\n\t\tif output == \"standard\" {\n\t\t\tfmt.Println(\"\\n\\n==========\")\n\t\t\tfmt.Fprintf(w, \"\\n Pod\\tNamespace\\tRestarts\\t\")\n\t\t\tfmt.Fprintf(w, \"\\n \\t\\t\\t\")\n\t\t\tfor _, v := range so.Pods {\n\t\t\t\tfmt.Fprintf(w, \"\\n %v\\t%v\\t%v\\t\", v.Name, v.Namespace, v.Count)\n\t\t\t\tif v.Containers != nil && ishowContainers {\n\t\t\t\t\tfor _, vv := range v.Containers {\n\t\t\t\t\t\tfmt.Fprintf(w, \"\\n    └%v: %v\\t\\t\\t\", vv.Name, vv.Count)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tw.Flush()\n\t\t}\n\t}\n\tswitch output {\n\tcase \"json\":\n\t\tj, _ := json.MarshalIndent(so, \"\", \"  \")\n\t\tfmt.Println(string(j))\n\tcase \"yaml\":\n\t\ty, _ := yaml.Marshal(so)\n\t\tfmt.Println(string(y))\n\tdefault:\n\t\tfmt.Printf(\"\\n\")\n\t}\n\n}\n\n// sorting results\n// https://stackoverflow.com/a/18695740\ntype Container struct {\n\tName  string `yaml:\"name\" json:\"name\"`\n\tCount int32  `yaml:\"count\" json:\"count\"`\n}\n\ntype Containers []Container\n\nfunc (p Containers) Len() int           { return len(p) }\nfunc (p Containers) Less(i, j int) bool { return p[i].Count < p[j].Count }\nfunc (p Containers) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\n\ntype Item struct {\n\tName       string     `yaml:\"name\" json:\"name\"`\n\tCount      int32      `yaml:\"count\" json:\"count\"`\n\tNamespace  string     `yaml:\"namespace,omitempty\" json:\"namespace,omitempty\"`\n\tContainers Containers `yaml:\"containers,omitempty\" json:\"containers,omitempty\"`\n}\n\ntype ItemList []Item\n\nfunc (p ItemList) Len() int           { return len(p) }\nfunc (p ItemList) Less(i, j int) bool { return p[i].Count < p[j].Count }\nfunc (p ItemList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\n\nfunc returnSortedLimit(data map[string]int32, limit int, parseNS bool, containers map[string]map[string]int32) ItemList {\n\til := make(ItemList, len(data))\n\ti := 0\n\tfor k, v := range data {\n\t\tif parseNS {\n\t\t\t// split the Name so we can display the pod an namespace separately\n\t\t\t// only used for pod items\n\t\t\ts := strings.Split(k, \":\")\n\t\t\til[i] = Item{s[1], v, s[0], createContainerSlice(containers[k])}\n\t\t} else {\n\t\t\til[i] = Item{k, v, \"\", nil}\n\t\t}\n\t\ti++\n\t}\n\tsort.Sort(sort.Reverse(il))\n\tif len(il) <= limit || limit == 0 {\n\t\treturn il\n\t} else {\n\t\treturn il[0:limit]\n\t}\n}\n\nfunc createContainerSlice(containers map[string]int32) []Container {\n\tif containers != nil {\n\t\tc := make(Containers, len(containers))\n\t\ti := 0\n\t\tfor k, v := range containers {\n\t\t\tc[i] = Container{k, v}\n\t\t\ti++\n\t\t}\n\t\tsort.Sort(sort.Reverse(c))\n\t\treturn c\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "cmd/printer_test.go",
    "content": "package cmd\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc Test_returnSortedLimit(t *testing.T) {\n\ttype args struct {\n\t\tdata       map[string]int32\n\t\tlimit      int\n\t\tparseNS    bool\n\t\tcontainers map[string]map[string]int32\n\t}\n\ttests := []struct {\n\t\tname string\n\t\targs args\n\t\twant ItemList\n\t}{\n\t\t{\n\t\t\tname: \"test1\",\n\t\t\targs: args{\n\t\t\t\tdata: map[string]int32{\n\t\t\t\t\t\"test1\": 5,\n\t\t\t\t\t\"test2\": 7,\n\t\t\t\t\t\"test3\": 8,\n\t\t\t\t\t\"test4\": 9,\n\t\t\t\t\t\"test5\": 0,\n\t\t\t\t\t\"test6\": 4,\n\t\t\t\t},\n\t\t\t\tlimit:      5,\n\t\t\t\tparseNS:    false,\n\t\t\t\tcontainers: nil,\n\t\t\t},\n\t\t\twant: ItemList{\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"test4\",\n\t\t\t\t\tCount:      9,\n\t\t\t\t\tNamespace:  \"\",\n\t\t\t\t\tContainers: nil,\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"test3\",\n\t\t\t\t\tCount:      8,\n\t\t\t\t\tNamespace:  \"\",\n\t\t\t\t\tContainers: nil,\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"test2\",\n\t\t\t\t\tCount:      7,\n\t\t\t\t\tNamespace:  \"\",\n\t\t\t\t\tContainers: nil,\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"test1\",\n\t\t\t\t\tCount:      5,\n\t\t\t\t\tNamespace:  \"\",\n\t\t\t\t\tContainers: nil,\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"test6\",\n\t\t\t\t\tCount:      4,\n\t\t\t\t\tNamespace:  \"\",\n\t\t\t\t\tContainers: nil,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"test2\",\n\t\t\targs: args{\n\t\t\t\tdata: map[string]int32{\n\t\t\t\t\t\"test1:pod1\": 5,\n\t\t\t\t\t\"test2:pod2\": 7,\n\t\t\t\t\t\"test2:pod3\": 8,\n\t\t\t\t\t\"test1:pod4\": 9,\n\t\t\t\t\t\"test2:pod5\": 0,\n\t\t\t\t\t\"test1:pod6\": 4,\n\t\t\t\t},\n\t\t\t\tlimit:   5,\n\t\t\t\tparseNS: true,\n\t\t\t\tcontainers: map[string]map[string]int32{\n\t\t\t\t\t\"test1:pod1\": {\"container1\": 5},\n\t\t\t\t\t\"test2:pod2\": {\"container1\": 7},\n\t\t\t\t\t\"test2:pod3\": {\"container1\": 8},\n\t\t\t\t\t\"test1:pod4\": {\"container3\": 2, \"container1\": 4, \"container2\": 3},\n\t\t\t\t\t\"test2:pod5\": {\"container1\": 0},\n\t\t\t\t\t\"test1:pod6\": {\"container1\": 4},\n\t\t\t\t},\n\t\t\t},\n\t\t\twant: ItemList{\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"pod4\",\n\t\t\t\t\tCount:      9,\n\t\t\t\t\tNamespace:  \"test1\",\n\t\t\t\t\tContainers: Containers{Container{\"container1\", 4}, Container{\"container2\", 3}, Container{\"container3\", 2}},\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"pod3\",\n\t\t\t\t\tCount:      8,\n\t\t\t\t\tNamespace:  \"test2\",\n\t\t\t\t\tContainers: Containers{Container{\"container1\", 8}},\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"pod2\",\n\t\t\t\t\tCount:      7,\n\t\t\t\t\tNamespace:  \"test2\",\n\t\t\t\t\tContainers: Containers{Container{\"container1\", 7}},\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"pod1\",\n\t\t\t\t\tCount:      5,\n\t\t\t\t\tNamespace:  \"test1\",\n\t\t\t\t\tContainers: Containers{Container{\"container1\", 5}},\n\t\t\t\t},\n\t\t\t\tItem{\n\t\t\t\t\tName:       \"pod6\",\n\t\t\t\t\tCount:      4,\n\t\t\t\t\tNamespace:  \"test1\",\n\t\t\t\t\tContainers: Containers{Container{\"container1\", 4}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := returnSortedLimit(tt.args.data, tt.args.limit, tt.args.parseNS, tt.args.containers); !reflect.DeepEqual(got, tt.want) {\n\t\t\t\tt.Errorf(\"returnSortedLimit() = %v, want %v\", got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "cmd/root.go",
    "content": "package cmd\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar inamespace []string\nvar ilabels []string\nvar ishowContainers bool\nvar limitFlag int\nvar output string\n\nvar rootCmd = &cobra.Command{\n\tUse:   \"kurt\",\n\tShort: \"KUbernetes Restart Tracker\",\n\tLong: `kurt: KUbernetes Restart Tracker\n\nA restart tracker that gives context to what is restarting in your cluster\n`,\n}\n\nfunc init() {\n\trootCmd.PersistentFlags().StringSliceVarP(&inamespace, \"namespace\", \"n\", []string{\"\"}, \"Specify namespace for kurt to collect restart metrics.\\nLeave blank to collect in all namespaces.\")\n\trootCmd.PersistentFlags().StringSliceVarP(&ilabels, \"label\", \"l\", []string{\"\"}, \"Specify multiple times for the label keys you want to see.\\nFor example: \\\"kurt all -l app\\\"\")\n\trootCmd.PersistentFlags().IntVarP(&limitFlag, \"limit\", \"c\", 5, \"Limit the number of resources you want to see. Set limit to 0 for no limits. Must be positive.\\nFor example: \\\"kurt all -c=10\\\"\")\n\trootCmd.PersistentFlags().StringVarP(&output, \"output\", \"o\", \"standard\", \"Specify output type. Options are: json, yaml, standard\\nFor example: \\\"kurt all -o json\\\"\")\n\n\t// command specific flags\n\tcmdPods.PersistentFlags().BoolVarP(&ishowContainers, \"show-containers\", \"\", false, \"Show specific container restart counts for pods\\nFor example: \\\"kurt pods --show-containers\\\"\")\n\tcmdAll.PersistentFlags().BoolVarP(&ishowContainers, \"show-containers\", \"\", false, \"Show specific container restart counts for pods\\nFor example: \\\"kurt pods --show-containers\\\"\")\n\n\tif strings.HasPrefix(filepath.Base(os.Args[0]), \"kubectl-\") {\n\t\trootCmd.SetUsageTemplate(strings.NewReplacer(\n\t\t\t\"{{.UseLine}}\", \"kubectl {{.UseLine}}\",\n\t\t\t\"{{.CommandPath}}\", \"kubectl {{.CommandPath}}\").Replace(rootCmd.UsageTemplate()))\n\t}\n\n}\n\nfunc Execute() {\n\tcobra.CheckErr(rootCmd.Execute())\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module kurt\n\ngo 1.23.0\n\ntoolchain go1.23.4\n\nrequire (\n\tgithub.com/spf13/cobra v1.8.1\n\tgopkg.in/yaml.v2 v2.4.0\n\tk8s.io/apimachinery v0.32.1\n\tk8s.io/client-go v0.32.1\n)\n\nrequire (\n\tgithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect\n\tgithub.com/emicklei/go-restful/v3 v3.12.1 // indirect\n\tgithub.com/fxamacker/cbor/v2 v2.7.0 // indirect\n\tgithub.com/go-logr/logr v1.4.2 // indirect\n\tgithub.com/go-openapi/jsonpointer v0.21.0 // indirect\n\tgithub.com/go-openapi/jsonreference v0.21.0 // indirect\n\tgithub.com/go-openapi/swag v0.23.0 // indirect\n\tgithub.com/gogo/protobuf v1.3.2 // indirect\n\tgithub.com/golang/protobuf v1.5.4 // indirect\n\tgithub.com/google/gnostic-models v0.6.9 // indirect\n\tgithub.com/google/go-cmp v0.6.0 // indirect\n\tgithub.com/google/gofuzz v1.2.0 // indirect\n\tgithub.com/google/uuid v1.6.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/josharian/intern v1.0.0 // indirect\n\tgithub.com/json-iterator/go v1.1.12 // indirect\n\tgithub.com/mailru/easyjson v0.9.0 // indirect\n\tgithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect\n\tgithub.com/modern-go/reflect2 v1.0.2 // indirect\n\tgithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect\n\tgithub.com/pkg/errors v0.9.1 // indirect\n\tgithub.com/spf13/pflag v1.0.5 // indirect\n\tgithub.com/x448/float16 v0.8.4 // indirect\n\tgolang.org/x/net v0.36.0 // indirect\n\tgolang.org/x/oauth2 v0.24.0 // indirect\n\tgolang.org/x/sys v0.30.0 // indirect\n\tgolang.org/x/term v0.29.0 // indirect\n\tgolang.org/x/text v0.22.0 // indirect\n\tgolang.org/x/time v0.8.0 // indirect\n\tgoogle.golang.org/protobuf v1.36.0 // indirect\n\tgopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect\n\tgopkg.in/inf.v0 v0.9.1 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n\tk8s.io/api v0.32.1 // indirect\n\tk8s.io/klog/v2 v2.130.1 // indirect\n\tk8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect\n\tk8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect\n\tsigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect\n\tsigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect\n\tsigs.k8s.io/yaml v1.4.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=\ngithub.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=\ngithub.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=\ngithub.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=\ngithub.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=\ngithub.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=\ngithub.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=\ngithub.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=\ngithub.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=\ngithub.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=\ngithub.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=\ngithub.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=\ngithub.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=\ngithub.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=\ngithub.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=\ngithub.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=\ngithub.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=\ngithub.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=\ngithub.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=\ngithub.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=\ngithub.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=\ngithub.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=\ngithub.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=\ngithub.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=\ngithub.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=\ngithub.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=\ngithub.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=\ngithub.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=\ngithub.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=\ngithub.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=\ngithub.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=\ngithub.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=\ngithub.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=\ngithub.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=\ngithub.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=\ngithub.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=\ngithub.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=\ngolang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=\ngolang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=\ngolang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=\ngolang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=\ngolang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=\ngolang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=\ngolang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=\ngolang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=\ngolang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=\ngoogle.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=\ngopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=\ngopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=\ngopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=\ngopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=\ngopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nk8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=\nk8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=\nk8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=\nk8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=\nk8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=\nk8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=\nk8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=\nk8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=\nk8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg=\nk8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=\nk8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=\nk8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=\nsigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=\nsigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=\nsigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=\nsigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=\nsigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=\nsigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=\n"
  },
  {
    "path": "internal/version/version.go",
    "content": "package version\n\nimport (\n\t\"fmt\"\n\t\"runtime\"\n)\n\n// NOTE: these variables are injected at build time\nvar (\n\tversion           string = \"development\"\n\tgitSHA, buildTime string\n\tbuild             Build\n)\n\ntype Build struct {\n\tVersion   string `json:\"version,omitempty\"`\n\tGitSHA    string `json:\"git,omitempty\"`\n\tBuildTime string `json:\"buildTime,omitempty\"`\n\tGoVersion string `json:\"goversion,omitempty\"`\n}\n\nfunc initBuild() {\n\tbuild.Version = version\n\tif len(gitSHA) >= 7 {\n\t\tbuild.GitSHA = gitSHA[:7]\n\t}\n\tbuild.BuildTime = buildTime\n\tbuild.GoVersion = runtime.Version()\n}\n\nfunc Version() string {\n\tinitBuild()\n\treturn fmt.Sprintf(\"%s\\n%s\", build.Version, build)\n}\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"kurt/cmd\"\n)\n\nfunc main() {\n\tcmd.Execute()\n}\n"
  },
  {
    "path": "tests/e2e.sh",
    "content": "#!/bin/bash\nset -eou pipefail\n\nkubectl apply -f tests/test.yml --wait\nkubectl wait --for=condition=Ready pod/nginx -n test1\nkubectl wait --for=condition=Ready pod/apache -n test2\n\n# Generate some pod restarts\nkubectl exec nginx -n test1 -- bash -c \"kill 1\"\n\nkubectl exec apache -n test2 -- bash -c \"kill 1\"\n\nsleep 5\nkubectl exec nginx -n test1 -- bash -c \"kill 1\"\n\necho \"[!] wait for pods to finish restarting...\"\nsleep 30\n\nNGINX_RESTARTS=$(./kurt pods -n test1 -o json | jq '.pods[0].count')\nif [ $NGINX_RESTARTS -eq 2 ]; then\n    echo \"[+] Correct number of restarts for nginx 👍\"\nelse\n    echo \"[!] Incorrect number of restarts for nginx: $NGINX_RESTARTS\"\n    exit 1\nfi\n\nAPACHE_RESTARTS=$(./kurt pods -n test2 -o json | jq '.pods[0].count')\nif [ $APACHE_RESTARTS -eq 1 ]; then\n    echo \"[+] Correct number of restarts for apache 👍\"\nelse\n    echo \"[!] Incorrect number of restarts for apache: $APACHE_RESTARTS\"\n    exit 1\nfi\n\necho \"[+] Cleaning up...\"\nkubectl delete -f tests/test.yml"
  },
  {
    "path": "tests/test.yml",
    "content": "kind: Namespace\napiVersion: v1\nmetadata:\n  name: test1\n---\nkind: Namespace\napiVersion: v1\nmetadata:\n  name: test2\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: nginx\n  namespace: test1\nspec:\n  containers:\n  - name: nginx\n    image: nginx:latest\n---\napiVersion: v1\nkind: Pod\nmetadata:\n  name: apache\n  namespace: test2\nspec:\n  containers:\n  - name: apache\n    image: httpd:latest"
  }
]